mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-10 03:34:06 +00:00
Compare commits
48 Commits
5.0.0-ALPH
...
4.10.0
Author | SHA1 | Date | |
---|---|---|---|
0d5287bf0b | |||
a9361b3f8b | |||
6e4c62744e | |||
d74824c8d5 | |||
d4eb73abe9 | |||
2a910c1cc2 | |||
cd04a3db2e | |||
572def9245 | |||
20f5bed926 | |||
14d17a9546 | |||
92e47b98f8 | |||
b84c110819 | |||
4fadb63f67 | |||
c83f0896ac | |||
0d29a138fb | |||
421379fc77 | |||
293cea7714 | |||
15645759e9 | |||
7df2719fce | |||
10b8dcfdd1 | |||
c1fbac412e | |||
cd4bb91676 | |||
2be527060f | |||
6f68c6d8a0 | |||
ac16378410 | |||
1f9dfa77bf | |||
fc56c041f3 | |||
22486dd75e | |||
37ec1193ea | |||
def2f8c145 | |||
ed7c95549d | |||
4650a3bb22 | |||
5e5661de75 | |||
e2f1b10165 | |||
455f9fa92e | |||
dec188d4ad | |||
2db3498891 | |||
f448b2e685 | |||
6a0c54f850 | |||
77a18d0aea | |||
140a809c40 | |||
cb7c136035 | |||
3f7d8a3777 | |||
3c55db531d | |||
93d4475111 | |||
7804172846 | |||
481bda8cd5 | |||
d1c75da14b |
8
.github/workflows/build-docker-image.yml
vendored
8
.github/workflows/build-docker-image.yml
vendored
@ -46,7 +46,7 @@ jobs:
|
||||
run: echo ::set-output name=NAME::$(echo "${GITHUB_REPOSITORY,,}")
|
||||
|
||||
- name: Build image for tag
|
||||
uses: docker/build-push-action@v3.1.1
|
||||
uses: docker/build-push-action@v3.2.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -59,7 +59,7 @@ jobs:
|
||||
|
||||
- name: Build image for major tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v3.1.1
|
||||
uses: docker/build-push-action@v3.2.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -72,7 +72,7 @@ jobs:
|
||||
|
||||
- name: Build image for minor tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v3.1.1
|
||||
uses: docker/build-push-action@v3.2.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -85,7 +85,7 @@ jobs:
|
||||
|
||||
- name: Build image for latest tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v3.1.1
|
||||
uses: docker/build-push-action@v3.2.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
|
2
.github/workflows/draft-release.yml
vendored
2
.github/workflows/draft-release.yml
vendored
@ -69,7 +69,7 @@ jobs:
|
||||
${{ github.workspace }}/build_info.json
|
||||
|
||||
- name: Create draft release
|
||||
uses: ncipollo/release-action@v1.10.0
|
||||
uses: ncipollo/release-action@v1.11.1
|
||||
with:
|
||||
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json
|
||||
commit: ${{ github.sha }}
|
||||
|
@ -18,6 +18,32 @@ Larger contributions like feature additions should be preceded by a [Change Prop
|
||||
## Other things you'll need
|
||||
- [git](https://git-scm.com/)
|
||||
|
||||
## Choosing a target branch
|
||||
PocketMine-MP has three primary branches of development.
|
||||
|
||||
| Type of change | `stable` | `next-minor` | `next-major` |
|
||||
|:---------------|:--------:|:------------:|:------------:|
|
||||
| Bug fixes | ✔️ | ✔️ | ✔️ |
|
||||
| Improvements to API docs | ✔️ | ✔️ | ✔️ |
|
||||
| Cleaning up code | ❌ | ✔️ | ✔️ |
|
||||
| Changing code formatting or style | ❌ | ✔️ | ✔️ |
|
||||
| Addition of new core features | ❌ | 🟡 Only if non-disruptive | ✔️ |
|
||||
| Changing core behaviour (e.g. making something use threads) | ❌ | ✔️ | ✔️ |
|
||||
| Addition of new configuration options | ❌ | 🟡 Only if optional | ✔️ |
|
||||
| Addition of new API classes, methods or constants | ❌ | ✔️ | ✔️ |
|
||||
| Deprecating API classes, methods or constants | ❌ | ✔️ | ✔️ |
|
||||
| Adding optional parameters to an API method | ❌ | ✔️ | ✔️ |
|
||||
| Changing API behaviour | ❌ | 🟡 Only if backwards-compatible | ✔️ |
|
||||
| Removal of API | ❌ | ❌ | ✔️ |
|
||||
| Backwards-incompatible API change (e.g. renaming a method) | ❌ | ❌ | ✔️ |
|
||||
|
||||
### Notes
|
||||
- **Non-disruptive** means that usage should not be significantly altered by the change.
|
||||
- Examples of **non-disruptive** changes include adding new commands, or gameplay features like blocks and items.
|
||||
- Examples of **disruptive** changes include changing the way the server is run, world format changes (since those require downtime for the user to convert their world).
|
||||
- **API** includes all public and protected classes, functions and constants (unless marked as `@internal`).
|
||||
- Private members are not part of the API, **unless in a trait**.
|
||||
|
||||
## Making a pull request
|
||||
The basic procedure to create a pull request is:
|
||||
1. [Fork the repository on GitHub](https://github.com/pmmp/PocketMine-MP/fork). This gives you your own copy of the repository to make changes to.
|
||||
|
Submodule build/php updated: cf79c01722...14ed8eaadd
14
changelogs/4.10.md
Normal file
14
changelogs/4.10.md
Normal file
@ -0,0 +1,14 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.40**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.10.0
|
||||
Released 26th October 2022.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.19.40.
|
||||
- Removed support for older versions.
|
@ -12,3 +12,25 @@ Released 20th September 2022.
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.19.30.
|
||||
- Removed support for older versions.
|
||||
|
||||
# 4.9.1
|
||||
Released 11th October 2022.
|
||||
|
||||
## Documentation
|
||||
- Added and improved documentation for many API methods in `Player` and `Block`.
|
||||
- Added missing `@internal` tag for `TaskHandler->setNextRun()`, `TaskHandler->remove()` and `TaskHandler->run()`.
|
||||
|
||||
## Fixes
|
||||
- Flight state is now locked by the server in spectator mode. This prevents any attempt by the client to toggle flight mode.
|
||||
- Fixed entity health exceeding its max health after the expiry of Health Boost effect.
|
||||
- Fixed burp sound not being played when a player eats food.
|
||||
- Fixed placement conditions for mushrooms - they can now only be placed when the light level at the target is <= 12, or on podzol or mycelium.
|
||||
- Fixed sign text appearing to change colour and/or glow when using dye on a sign - since this feature is not yet implemented, no change should occur.
|
||||
- Fixed players drowning when sprint-swimming on the surface of water.
|
||||
|
||||
## Internals
|
||||
- Added more detailed debug logging during the player login sequence.
|
||||
- Silenced debug spam during `PreSpawnPacketHandler`, considerably reducing debug noise when players join.
|
||||
- Fixed an edge case in `InventoryManager->removeWindow()`. This bug didn't have any effect on stable versions, but caused a `next-minor` development version to crash.
|
||||
- `Item`s returned by event getters are now cloned if modifying the result will have no useful side effects.
|
||||
- Updated `pocketmine/bedrock-data` to [`1.11.1`](https://github.com/pmmp/BedrockData/tree/1.11.1%2Bbedrock-1.19.30), which reduces bandwidth consumption during logins by not sending useless biome generation data.
|
||||
|
@ -34,8 +34,8 @@
|
||||
"adhocore/json-comment": "^1.1",
|
||||
"fgrosse/phpasn1": "^2.3",
|
||||
"netresearch/jsonmapper": "^4.0",
|
||||
"pocketmine/bedrock-data": "~1.11.0+bedrock-1.19.30",
|
||||
"pocketmine/bedrock-protocol": "~13.0.0+bedrock-1.19.30",
|
||||
"pocketmine/bedrock-data": "~1.12.0+bedrock-1.19.40",
|
||||
"pocketmine/bedrock-protocol": "~14.0.0+bedrock-1.19.40",
|
||||
"pocketmine/binaryutils": "^0.2.1",
|
||||
"pocketmine/callback-validator": "^1.0.2",
|
||||
"pocketmine/classloader": "^0.2.0",
|
||||
@ -53,7 +53,7 @@
|
||||
"webmozart/path-util": "^2.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.8.5",
|
||||
"phpstan/phpstan": "1.8.11",
|
||||
"phpstan/phpstan-phpunit": "^1.1.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.2.0",
|
||||
"phpunit/phpunit": "^9.2"
|
||||
|
92
composer.lock
generated
92
composer.lock
generated
@ -4,20 +4,20 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "0f6c845836d4ec6f221415d2f9dd1fc5",
|
||||
"content-hash": "ed062ef1dc3113ad2a75ba4d4d5e174f",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/json-comment",
|
||||
"version": "1.1.2",
|
||||
"version": "1.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/adhocore/php-json-comment.git",
|
||||
"reference": "fc2f76979f0a44a5f5bc2a2b600d0762fe0e78e7"
|
||||
"reference": "651023f9fe52e9efa2198cbaf6e481d1968e2377"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/adhocore/php-json-comment/zipball/fc2f76979f0a44a5f5bc2a2b600d0762fe0e78e7",
|
||||
"reference": "fc2f76979f0a44a5f5bc2a2b600d0762fe0e78e7",
|
||||
"url": "https://api.github.com/repos/adhocore/php-json-comment/zipball/651023f9fe52e9efa2198cbaf6e481d1968e2377",
|
||||
"reference": "651023f9fe52e9efa2198cbaf6e481d1968e2377",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -51,15 +51,19 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/adhocore/php-json-comment/issues",
|
||||
"source": "https://github.com/adhocore/php-json-comment/tree/1.1.2"
|
||||
"source": "https://github.com/adhocore/php-json-comment/tree/1.2.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://paypal.me/ji10",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/adhocore",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-04-09T03:06:06+00:00"
|
||||
"time": "2022-10-02T11:22:07+00:00"
|
||||
},
|
||||
{
|
||||
"name": "brick/math",
|
||||
@ -245,16 +249,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-data",
|
||||
"version": "1.11.0+bedrock-1.19.30",
|
||||
"version": "1.12.0+bedrock-1.19.40",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockData.git",
|
||||
"reference": "2cca1d48421db20740ffd1ce67b40b91acc61187"
|
||||
"reference": "32690f1dac05608b558fe7c40b6d634772c8e416"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/2cca1d48421db20740ffd1ce67b40b91acc61187",
|
||||
"reference": "2cca1d48421db20740ffd1ce67b40b91acc61187",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/32690f1dac05608b558fe7c40b6d634772c8e416",
|
||||
"reference": "32690f1dac05608b558fe7c40b6d634772c8e416",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -265,22 +269,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.19.30"
|
||||
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.19.40"
|
||||
},
|
||||
"time": "2022-09-20T18:19:22+00:00"
|
||||
"time": "2022-10-25T21:45:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-protocol",
|
||||
"version": "13.0.0+bedrock-1.19.30",
|
||||
"version": "14.0.0+bedrock-1.19.40",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockProtocol.git",
|
||||
"reference": "94de2221676ca717587e1ff4e45445c24ada1749"
|
||||
"reference": "b455a742779fee94d25f931cc2cbf6b2c5d61c1f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/94de2221676ca717587e1ff4e45445c24ada1749",
|
||||
"reference": "94de2221676ca717587e1ff4e45445c24ada1749",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/b455a742779fee94d25f931cc2cbf6b2c5d61c1f",
|
||||
"reference": "b455a742779fee94d25f931cc2cbf6b2c5d61c1f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -294,7 +298,7 @@
|
||||
"ramsey/uuid": "^4.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.8.0",
|
||||
"phpstan/phpstan": "1.8.8",
|
||||
"phpstan/phpstan-phpunit": "^1.0.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.0.0",
|
||||
"phpunit/phpunit": "^9.5"
|
||||
@ -312,9 +316,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/bedrock-1.19.30"
|
||||
"source": "https://github.com/pmmp/BedrockProtocol/tree/bedrock-1.19.40"
|
||||
},
|
||||
"time": "2022-09-20T18:35:00+00:00"
|
||||
"time": "2022-10-25T21:51:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/binaryutils",
|
||||
@ -1506,16 +1510,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.8.5",
|
||||
"version": "1.8.11",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "f6598a5ff12ca4499a836815e08b4d77a2ddeb20"
|
||||
"reference": "46e223dd68a620da18855c23046ddb00940b4014"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/f6598a5ff12ca4499a836815e08b4d77a2ddeb20",
|
||||
"reference": "f6598a5ff12ca4499a836815e08b4d77a2ddeb20",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/46e223dd68a620da18855c23046ddb00940b4014",
|
||||
"reference": "46e223dd68a620da18855c23046ddb00940b4014",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1545,7 +1549,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan/issues",
|
||||
"source": "https://github.com/phpstan/phpstan/tree/1.8.5"
|
||||
"source": "https://github.com/phpstan/phpstan/tree/1.8.11"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1561,7 +1565,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-09-07T16:05:32+00:00"
|
||||
"time": "2022-10-24T15:45:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-phpunit",
|
||||
@ -1617,21 +1621,21 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-strict-rules",
|
||||
"version": "1.4.3",
|
||||
"version": "1.4.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
|
||||
"reference": "431b3d6e8040075de196680cd5bc95735987b4ae"
|
||||
"reference": "23e5f377ee6395a1a04842d3d6ed4bd25e7b44a6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/431b3d6e8040075de196680cd5bc95735987b4ae",
|
||||
"reference": "431b3d6e8040075de196680cd5bc95735987b4ae",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/23e5f377ee6395a1a04842d3d6ed4bd25e7b44a6",
|
||||
"reference": "23e5f377ee6395a1a04842d3d6ed4bd25e7b44a6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0",
|
||||
"phpstan/phpstan": "^1.8.3"
|
||||
"phpstan/phpstan": "^1.8.6"
|
||||
},
|
||||
"require-dev": {
|
||||
"nikic/php-parser": "^4.13.0",
|
||||
@ -1659,9 +1663,9 @@
|
||||
"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/1.4.3"
|
||||
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.4.4"
|
||||
},
|
||||
"time": "2022-08-26T15:05:46+00:00"
|
||||
"time": "2022-09-21T11:38:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
@ -1983,16 +1987,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "9.5.24",
|
||||
"version": "9.5.25",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "d0aa6097bef9fd42458a9b3c49da32c6ce6129c5"
|
||||
"reference": "3e6f90ca7e3d02025b1d147bd8d4a89fd4ca8a1d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d0aa6097bef9fd42458a9b3c49da32c6ce6129c5",
|
||||
"reference": "d0aa6097bef9fd42458a9b3c49da32c6ce6129c5",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3e6f90ca7e3d02025b1d147bd8d4a89fd4ca8a1d",
|
||||
"reference": "3e6f90ca7e3d02025b1d147bd8d4a89fd4ca8a1d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2014,14 +2018,14 @@
|
||||
"phpunit/php-timer": "^5.0.2",
|
||||
"sebastian/cli-parser": "^1.0.1",
|
||||
"sebastian/code-unit": "^1.0.6",
|
||||
"sebastian/comparator": "^4.0.5",
|
||||
"sebastian/comparator": "^4.0.8",
|
||||
"sebastian/diff": "^4.0.3",
|
||||
"sebastian/environment": "^5.1.3",
|
||||
"sebastian/exporter": "^4.0.3",
|
||||
"sebastian/exporter": "^4.0.5",
|
||||
"sebastian/global-state": "^5.0.1",
|
||||
"sebastian/object-enumerator": "^4.0.3",
|
||||
"sebastian/resource-operations": "^3.0.3",
|
||||
"sebastian/type": "^3.1",
|
||||
"sebastian/type": "^3.2",
|
||||
"sebastian/version": "^3.0.2"
|
||||
},
|
||||
"suggest": {
|
||||
@ -2065,7 +2069,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.24"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.25"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2075,9 +2079,13 @@
|
||||
{
|
||||
"url": "https://github.com/sebastianbergmann",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-08-30T07:42:16+00:00"
|
||||
"time": "2022-09-25T03:44:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
|
@ -31,8 +31,8 @@ use function str_repeat;
|
||||
|
||||
final class VersionInfo{
|
||||
public const NAME = "PocketMine-MP";
|
||||
public const BASE_VERSION = "4.9.1";
|
||||
public const IS_DEVELOPMENT_BUILD = true;
|
||||
public const BASE_VERSION = "4.10.0";
|
||||
public const IS_DEVELOPMENT_BUILD = false;
|
||||
public const BUILD_CHANNEL = "stable";
|
||||
|
||||
private function __construct(){
|
||||
|
@ -78,25 +78,47 @@ class Block{
|
||||
$this->position = clone $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object containing information about how to identify and store this block type, such as its legacy
|
||||
* numeric ID(s), tile type (if any), and legacy variant metadata.
|
||||
*/
|
||||
public function getIdInfo() : BlockIdentifier{
|
||||
return $this->idInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the printable English name of the block.
|
||||
*/
|
||||
public function getName() : string{
|
||||
return $this->fallbackName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
* Returns the legacy numeric Minecraft block ID.
|
||||
*/
|
||||
public function getId() : int{
|
||||
return $this->idInfo->getBlockId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* Returns the full blockstate ID of this block. This is a compact way of representing a blockstate used to store
|
||||
* blocks in chunks at runtime.
|
||||
*
|
||||
* This ID can be used to later obtain a copy of this block using {@link BlockFactory::get()}.
|
||||
*/
|
||||
public function getFullId() : int{
|
||||
return ($this->getId() << self::INTERNAL_METADATA_BITS) | $this->getMeta();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the block as an item.
|
||||
* State information such as facing, powered/unpowered, open/closed, etc., is discarded.
|
||||
* Type information such as colour, wood type, etc. is preserved.
|
||||
*/
|
||||
public function asItem() : Item{
|
||||
return ItemFactory::getInstance()->get(
|
||||
$this->idInfo->getItemId(),
|
||||
@ -104,6 +126,12 @@ class Block{
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
* Returns the legacy Minecraft block meta value. This is a mixed-purpose value, which is used to store different
|
||||
* things for different blocks.
|
||||
*/
|
||||
public function getMeta() : int{
|
||||
$stateMeta = $this->writeStateToMeta();
|
||||
assert(($stateMeta & ~$this->getStateBitmask()) === 0);
|
||||
@ -116,6 +144,7 @@ class Block{
|
||||
|
||||
/**
|
||||
* Returns a bitmask used to extract state bits from block metadata.
|
||||
* This is used to remove unwanted information from the legacy meta value when getting the block as an item.
|
||||
*/
|
||||
public function getStateBitmask() : int{
|
||||
return 0;
|
||||
@ -143,6 +172,12 @@ class Block{
|
||||
$this->collisionBoxes = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes information about the block into the world. This writes the blockstate ID into the chunk, and creates
|
||||
* and/or removes tiles as necessary.
|
||||
*
|
||||
* Note: Do not call this directly. Pass the block to {@link World::setBlock()} instead.
|
||||
*/
|
||||
public function writeStateToWorld() : void{
|
||||
$this->position->getWorld()->getOrLoadChunkAtPosition($this->position)->setFullBlock($this->position->x & Chunk::COORD_MASK, $this->position->y, $this->position->z & Chunk::COORD_MASK, $this->getFullId());
|
||||
|
||||
@ -167,7 +202,7 @@ class Block{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a type ID that identifies this type of block. This does not include information like facing, colour,
|
||||
* Returns a type ID that identifies this type of block. This does not include information like facing, open/closed,
|
||||
* powered/unpowered, etc.
|
||||
*/
|
||||
public function getTypeId() : int{
|
||||
@ -198,22 +233,36 @@ class Block{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this block can be replaced by another block placed in the same position.
|
||||
*/
|
||||
public function canBeReplaced() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this block can replace the given block in the given placement conditions.
|
||||
* This is used to allow slabs of the same type to combine into double slabs.
|
||||
*/
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
|
||||
return $blockReplace->canBeReplaced();
|
||||
}
|
||||
|
||||
/**
|
||||
* Places the Block, using block space and block target, and side. Returns if the block has been placed.
|
||||
* Generates a block transaction to set all blocks affected by placing this block. Usually this is just the block
|
||||
* itself, but may be multiple blocks in some cases (such as doors).
|
||||
*
|
||||
* @return bool whether the placement should go ahead
|
||||
*/
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$tx->addBlock($blockReplace->position, $this);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called immediately after the block has been placed in the world. Since placement uses a block transaction, some
|
||||
* things may not be possible until after the transaction has been executed.
|
||||
*/
|
||||
public function onPostPlace() : void{
|
||||
|
||||
}
|
||||
@ -252,7 +301,7 @@ class Block{
|
||||
|
||||
/**
|
||||
* Called when this block is randomly updated due to chunk ticking.
|
||||
* WARNING: This will not be called if ticksRandomly() does not return true!
|
||||
* WARNING: This will not be called if {@link Block::ticksRandomly()} does not return true!
|
||||
*/
|
||||
public function onRandomTick() : void{
|
||||
|
||||
@ -273,8 +322,7 @@ class Block{
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this block is attacked (left-clicked). This is called when a player left-clicks the block to try and
|
||||
* start to break it in survival mode.
|
||||
* Called when this block is attacked (left-clicked) by a player attempting to start breaking it in survival.
|
||||
*
|
||||
* @return bool if an action took place, prevents starting to break the block if true.
|
||||
*/
|
||||
@ -282,11 +330,19 @@ class Block{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a multiplier applied to the velocity of entities moving on top of this block. A higher value will make
|
||||
* the block more slippery (like ice).
|
||||
*
|
||||
* @return float 0.0-1.0
|
||||
*/
|
||||
public function getFrictionFactor() : float{
|
||||
return 0.6;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of light emitted by this block.
|
||||
*
|
||||
* @return int 0-15
|
||||
*/
|
||||
public function getLightLevel() : int{
|
||||
@ -329,10 +385,6 @@ class Block{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function hasEntityCollision() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether entities can climb up this block.
|
||||
*/
|
||||
@ -340,10 +392,6 @@ class Block{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addVelocityToEntity(Entity $entity) : ?Vector3{
|
||||
return null;
|
||||
}
|
||||
|
||||
final public function getPosition() : Position{
|
||||
return $this->position;
|
||||
}
|
||||
@ -426,6 +474,7 @@ class Block{
|
||||
|
||||
/**
|
||||
* Returns the item that players will equip when middle-clicking on this block.
|
||||
* If addUserData is true, additional data may be added, such as banner patterns, chest contents, etc.
|
||||
*/
|
||||
public function getPickedItem(bool $addUserData = false) : Item{
|
||||
$item = $this->asItem();
|
||||
@ -549,7 +598,7 @@ class Block{
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for collision against an AxisAlignedBB
|
||||
* Returns whether any of the block's collision boxes intersect with the given AxisAlignedBB.
|
||||
*/
|
||||
public function collidesWithBB(AxisAlignedBB $bb) : bool{
|
||||
foreach($this->getCollisionBoxes() as $bb2){
|
||||
@ -561,10 +610,21 @@ class Block{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the block has actions to be executed when an entity enters its cell (full cube space).
|
||||
*
|
||||
* @see Block::onEntityInside()
|
||||
*/
|
||||
public function hasEntityCollision() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an entity's bounding box clips inside this block's cell. Note that the entity may not be intersecting
|
||||
* with the collision box or bounding box.
|
||||
*
|
||||
* WARNING: This will not be called if {@link Block::hasEntityCollision()} returns false.
|
||||
*
|
||||
* @return bool Whether the block is still the same after the intersection. If it changed (e.g. due to an explosive
|
||||
* being ignited), this should return false.
|
||||
*/
|
||||
@ -572,6 +632,19 @@ class Block{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a direction vector describing which way an entity intersecting this block should be pushed.
|
||||
* This is used by liquids to push entities in liquid currents.
|
||||
*
|
||||
* The returned vector is summed with vectors from every other block the entity is intersecting, and normalized to
|
||||
* produce a final direction vector.
|
||||
*
|
||||
* WARNING: This will not be called if {@link Block::hasEntityCollision()} does not return true!
|
||||
*/
|
||||
public function addVelocityToEntity(Entity $entity) : ?Vector3{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an entity lands on this block (usually due to falling).
|
||||
* @return float|null The new vertical velocity of the entity, or null if unchanged.
|
||||
@ -581,6 +654,13 @@ class Block{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of collision bounding boxes for this block.
|
||||
* These are used for:
|
||||
* - entity movement collision checks (to ensure entities can't clip through blocks)
|
||||
* - projectile flight paths
|
||||
* - block placement (to ensure the player can't place blocks inside itself or another entity)
|
||||
* - anti-cheat checks in plugins
|
||||
*
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
final public function getCollisionBoxes() : array{
|
||||
@ -611,6 +691,10 @@ class Block{
|
||||
return [AxisAlignedBB::one()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of support that the block can provide on the given face. This is used to determine whether
|
||||
* blocks placed on the given face can be supported by this block.
|
||||
*/
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::FULL();
|
||||
}
|
||||
@ -621,6 +705,10 @@ class Block{
|
||||
return count($bb) === 1 && $bb[0]->getAverageEdgeLength() >= 1 && $bb[0]->isCube();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a ray trace along the line between the two positions using the block's collision boxes.
|
||||
* Returns the intersection point closest to pos1, or null if no intersection occurred.
|
||||
*/
|
||||
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?RayTraceResult{
|
||||
$bbs = $this->getCollisionBoxes();
|
||||
if(count($bbs) === 0){
|
||||
|
@ -26,6 +26,10 @@ namespace pocketmine\block;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
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
|
||||
* collision boxes, and can't provide support for other blocks.
|
||||
*/
|
||||
abstract class Flowable extends Transparent{
|
||||
|
||||
public function canBeFlowedInto() : bool{
|
||||
|
@ -27,7 +27,7 @@ use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use function mt_rand;
|
||||
|
||||
class Melon extends Transparent{
|
||||
class Melon extends Opaque{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
|
@ -23,6 +23,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
/**
|
||||
* Opaque blocks do not allow light to pass through. They are usually collidable full-cube blocks.
|
||||
* Most blocks in Minecraft fall into this category.
|
||||
*/
|
||||
class Opaque extends Block{
|
||||
|
||||
public function isSolid() : bool{
|
||||
|
@ -43,7 +43,11 @@ class RedMushroom extends Flowable{
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$down = $this->getSide(Facing::DOWN);
|
||||
if(!$down->isTransparent()){
|
||||
$position = $this->getPosition();
|
||||
$lightLevel = $position->getWorld()->getFullLightAt($position->x, $position->y, $position->z);
|
||||
$downId = $down->getId();
|
||||
//TODO: nylium support
|
||||
if(($lightLevel <= 12 && !$down->isTransparent()) || $downId === BlockLegacyIds::MYCELIUM || $downId === BlockLegacyIds::PODZOL){
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,9 @@ use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use function count;
|
||||
|
||||
/**
|
||||
* Thin blocks behave like glass panes. They connect to full-cube blocks horizontally adjacent to them if possible.
|
||||
*/
|
||||
class Thin extends Transparent{
|
||||
/** @var bool[] facing => dummy */
|
||||
protected array $connections = [];
|
||||
|
@ -23,6 +23,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
/**
|
||||
* Transparent blocks do not block any light from propagating through them.
|
||||
*
|
||||
* Note: This does **not** imply that the block is **visually** transparent. For example, chests allow light to pass
|
||||
* through, but the player cannot see through them except at the edges.
|
||||
*/
|
||||
class Transparent extends Block{
|
||||
|
||||
public function isTransparent() : bool{
|
||||
|
@ -25,6 +25,9 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
|
||||
/**
|
||||
* Represents a block which is unrecognized or not implemented.
|
||||
*/
|
||||
class UnknownBlock extends Transparent{
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, BlockBreakInfo $breakInfo){
|
||||
|
@ -27,6 +27,7 @@ use pocketmine\block\utils\SignText;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\world\World;
|
||||
use function array_pad;
|
||||
use function array_slice;
|
||||
@ -42,6 +43,13 @@ use function sprintf;
|
||||
class Sign extends Spawnable{
|
||||
public const TAG_TEXT_BLOB = "Text";
|
||||
public const TAG_TEXT_LINE = "Text%d"; //sprintf()able
|
||||
public const TAG_TEXT_COLOR = "SignTextColor";
|
||||
public const TAG_GLOWING_TEXT = "IgnoreLighting";
|
||||
/**
|
||||
* This tag is set to indicate that MCPE-117835 has been addressed in whatever version this sign was created.
|
||||
* @see https://bugs.mojang.com/browse/MCPE-117835
|
||||
*/
|
||||
public const TAG_LEGACY_BUG_RESOLVE = "TextIgnoreLegacyBugResolved";
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
@ -111,5 +119,11 @@ class Sign extends Spawnable{
|
||||
|
||||
protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
|
||||
$nbt->setString(self::TAG_TEXT_BLOB, implode("\n", $this->text->getLines()));
|
||||
|
||||
//the following are not yet used by the server, but needed to roll back any changes to glowing state or colour
|
||||
//if the client uses dye on the sign
|
||||
$nbt->setInt(self::TAG_TEXT_COLOR, Binary::signInt(0xff_00_00_00));
|
||||
$nbt->setByte(self::TAG_GLOWING_TEXT, 0);
|
||||
$nbt->setByte(self::TAG_LEGACY_BUG_RESOLVE, 1);
|
||||
}
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ class SimpleCommandMap implements CommandMap{
|
||||
|
||||
public function register(string $fallbackPrefix, Command $command, ?string $label = null) : bool{
|
||||
if($label === null){
|
||||
$label = $command->getName();
|
||||
$label = $command->getLabel();
|
||||
}
|
||||
$label = trim($label);
|
||||
$fallbackPrefix = strtolower(trim($fallbackPrefix));
|
||||
|
@ -80,7 +80,7 @@ class HelpCommand extends VanillaCommand{
|
||||
$commands = [];
|
||||
foreach($sender->getServer()->getCommandMap()->getCommands() as $command){
|
||||
if($command->testPermissionSilent($sender)){
|
||||
$commands[$command->getName()] = $command;
|
||||
$commands[$command->getLabel()] = $command;
|
||||
}
|
||||
}
|
||||
ksort($commands, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
@ -95,7 +95,7 @@ class HelpCommand extends VanillaCommand{
|
||||
foreach($commands[$pageNumber - 1] as $command){
|
||||
$description = $command->getDescription();
|
||||
$descriptionString = $description instanceof Translatable ? $lang->translate($description) : $description;
|
||||
$sender->sendMessage(TextFormat::DARK_GREEN . "/" . $command->getName() . ": " . TextFormat::WHITE . $descriptionString);
|
||||
$sender->sendMessage(TextFormat::DARK_GREEN . "/" . $command->getLabel() . ": " . TextFormat::WHITE . $descriptionString);
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,7 +106,7 @@ class HelpCommand extends VanillaCommand{
|
||||
$lang = $sender->getLanguage();
|
||||
$description = $cmd->getDescription();
|
||||
$descriptionString = $description instanceof Translatable ? $lang->translate($description) : $description;
|
||||
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_header($cmd->getName())
|
||||
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_header($cmd->getLabel())
|
||||
->format(TextFormat::YELLOW . "--------- " . TextFormat::WHITE, TextFormat::YELLOW . " ---------"));
|
||||
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_description(TextFormat::WHITE . $descriptionString)
|
||||
->prefix(TextFormat::GOLD));
|
||||
|
@ -52,6 +52,7 @@ use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataCollection;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\MetadataProperty;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\PropertySyncData;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\timings\Timings;
|
||||
@ -1469,6 +1470,7 @@ abstract class Entity{
|
||||
return new NetworkAttribute($attr->getId(), $attr->getMinValue(), $attr->getMaxValue(), $attr->getValue(), $attr->getDefaultValue(), []);
|
||||
}, $this->attributeMap->getAll()),
|
||||
$this->getAllNetworkData(),
|
||||
new PropertySyncData([], []),
|
||||
[] //TODO: entity links
|
||||
));
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ use pocketmine\network\mcpe\protocol\types\command\CommandPermissions;
|
||||
use pocketmine\network\mcpe\protocol\types\DeviceOS;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\PropertySyncData;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\StringMetadataProperty;
|
||||
use pocketmine\network\mcpe\protocol\types\GameMode;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
@ -485,6 +486,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($this->getInventory()->getItemInHand())),
|
||||
GameMode::SURVIVAL,
|
||||
$this->getAllNetworkData(),
|
||||
new PropertySyncData([], []),
|
||||
UpdateAbilitiesPacket::create(CommandPermissions::NORMAL, PlayerPermissions::VISITOR, $this->getId() /* TODO: this should be unique ID */, [
|
||||
new UpdateAbilitiesPacketLayer(
|
||||
UpdateAbilitiesPacketLayer::LAYER_BASE,
|
||||
|
@ -56,6 +56,7 @@ use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\world\sound\BurpSound;
|
||||
use pocketmine\world\sound\EntityLandSound;
|
||||
use pocketmine\world\sound\EntityLongFallSound;
|
||||
use pocketmine\world\sound\EntityShortFallSound;
|
||||
@ -255,8 +256,7 @@ abstract class Living extends Entity{
|
||||
$size = $this->getInitialSizeInfo();
|
||||
if($this->isSwimming() || $this->isGliding()){
|
||||
$width = $size->getWidth();
|
||||
//we don't actually know an appropriate eye height for a swimming mob, but 2/3 should be good enough.
|
||||
$this->setSize((new EntitySizeInfo($width, $width, $width * 2 / 3))->scale($this->getScale()));
|
||||
$this->setSize((new EntitySizeInfo($width, $width, $width * 0.9))->scale($this->getScale()));
|
||||
}else{
|
||||
$this->setSize($size->scale($this->getScale()));
|
||||
}
|
||||
@ -320,6 +320,9 @@ abstract class Living extends Entity{
|
||||
foreach($consumable->getAdditionalEffects() as $effect){
|
||||
$this->effectManager->add($effect);
|
||||
}
|
||||
if($consumable instanceof FoodSource){
|
||||
$this->broadcastSound(new BurpSound());
|
||||
}
|
||||
|
||||
$consumable->onConsume($this);
|
||||
}
|
||||
|
@ -33,5 +33,8 @@ class HealthBoostEffect extends Effect{
|
||||
|
||||
public function remove(Living $entity, EffectInstance $instance) : void{
|
||||
$entity->setMaxHealth($entity->getMaxHealth() - 4 * $instance->getEffectLevel());
|
||||
if($entity->getHealth() > $entity->getMaxHealth()){
|
||||
$entity->setHealth($entity->getMaxHealth());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -117,7 +117,6 @@ class FallingBlock extends Entity{
|
||||
|
||||
$block = $world->getBlock($pos);
|
||||
if(!$block->canBeReplaced() || !$world->isInWorld($pos->getFloorX(), $pos->getFloorY(), $pos->getFloorZ()) || ($this->onGround && abs($this->location->y - $this->location->getFloorY()) > 0.001)){
|
||||
//FIXME: anvils are supposed to destroy torches
|
||||
$world->dropItem($this->location, $this->block->asItem());
|
||||
}else{
|
||||
$ev = new EntityBlockChangeEvent($this, $block, $blockTarget ?? $this->block);
|
||||
|
@ -98,8 +98,8 @@ class SplashPotion extends Throwable{
|
||||
|
||||
if($hasEffects){
|
||||
if(!$this->willLinger()){
|
||||
foreach($this->getWorld()->getNearbyEntities($this->boundingBox->expandedCopy(4.125, 2.125, 4.125), $this) as $entity){
|
||||
if($entity instanceof Living && $entity->isAlive()){
|
||||
foreach($this->getWorld()->getCollidingEntities($this->boundingBox->expandedCopy(4.125, 2.125, 4.125), $this) as $entity){
|
||||
if($entity instanceof Living){
|
||||
$distanceSquared = $entity->getEyePos()->distanceSquared($this->location);
|
||||
if($distanceSquared > 16){ //4 blocks
|
||||
continue;
|
||||
|
@ -72,7 +72,7 @@ class BlockBreakEvent extends BlockEvent implements Cancellable{
|
||||
* Returns the item used to destroy the block.
|
||||
*/
|
||||
public function getItem() : Item{
|
||||
return $this->item;
|
||||
return clone $this->item;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,7 +65,7 @@ class BlockPlaceEvent extends BlockEvent implements Cancellable{
|
||||
* Gets the item in hand
|
||||
*/
|
||||
public function getItem() : Item{
|
||||
return $this->item;
|
||||
return clone $this->item;
|
||||
}
|
||||
|
||||
public function getBlockReplaced() : Block{
|
||||
|
@ -69,7 +69,7 @@ class PlayerInteractEvent extends PlayerEvent implements Cancellable{
|
||||
}
|
||||
|
||||
public function getItem() : Item{
|
||||
return $this->item;
|
||||
return clone $this->item;
|
||||
}
|
||||
|
||||
public function getBlock() : Block{
|
||||
|
@ -60,6 +60,6 @@ class PlayerItemHeldEvent extends PlayerEvent implements Cancellable{
|
||||
* Returns the item in the slot that the player is trying to equip.
|
||||
*/
|
||||
public function getItem() : Item{
|
||||
return $this->item;
|
||||
return clone $this->item;
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ class PlayerItemUseEvent extends PlayerEvent implements Cancellable{
|
||||
* Returns the item used.
|
||||
*/
|
||||
public function getItem() : Item{
|
||||
return $this->item;
|
||||
return clone $this->item;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -259,7 +259,7 @@ class InventoryManager{
|
||||
|
||||
public function onClientRemoveWindow(int $id) : void{
|
||||
if($id === $this->lastInventoryNetworkId){
|
||||
if($id !== $this->pendingCloseWindowId){
|
||||
if(isset($this->windowMap[$id]) && $id !== $this->pendingCloseWindowId){
|
||||
$this->remove($id);
|
||||
$this->player->removeCurrentWindow();
|
||||
}
|
||||
|
@ -97,6 +97,7 @@ use pocketmine\network\mcpe\protocol\types\command\CommandPermissions;
|
||||
use pocketmine\network\mcpe\protocol\types\DimensionIds;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\Attribute as NetworkAttribute;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\MetadataProperty;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\PropertySyncData;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ContainerIds;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
|
||||
@ -869,7 +870,7 @@ class NetworkSession{
|
||||
//TODO: HACK! as of 1.18.10, the client responds differently to the same data ordered in different orders - for
|
||||
//example, sending HEIGHT in the list before FLAGS when unsetting the SWIMMING flag results in a hitbox glitch
|
||||
ksort($properties, SORT_NUMERIC);
|
||||
$this->sendDataPacket(SetActorDataPacket::create($entity->getId(), $properties, 0));
|
||||
$this->sendDataPacket(SetActorDataPacket::create($entity->getId(), $properties, new PropertySyncData([], []), 0));
|
||||
}
|
||||
|
||||
public function onEntityEffectAdded(Living $entity, EffectInstance $effect, bool $replacesOldEffect) : void{
|
||||
@ -888,11 +889,11 @@ class NetworkSession{
|
||||
public function syncAvailableCommands() : void{
|
||||
$commandData = [];
|
||||
foreach($this->server->getCommandMap()->getCommands() as $name => $command){
|
||||
if(isset($commandData[$command->getName()]) || $command->getName() === "help" || !$command->testPermissionSilent($this->player)){
|
||||
if(isset($commandData[$command->getLabel()]) || $command->getLabel() === "help" || !$command->testPermissionSilent($this->player)){
|
||||
continue;
|
||||
}
|
||||
|
||||
$lname = strtolower($command->getName());
|
||||
$lname = strtolower($command->getLabel());
|
||||
$aliases = $command->getAliases();
|
||||
$aliasObj = null;
|
||||
if(count($aliases) > 0){
|
||||
@ -900,7 +901,7 @@ class NetworkSession{
|
||||
//work around a client bug which makes the original name not show when aliases are used
|
||||
$aliases[] = $lname;
|
||||
}
|
||||
$aliasObj = new CommandEnum(ucfirst($command->getName()) . "Aliases", array_values($aliases));
|
||||
$aliasObj = new CommandEnum(ucfirst($command->getLabel()) . "Aliases", array_values($aliases));
|
||||
}
|
||||
|
||||
$description = $command->getDescription();
|
||||
@ -915,7 +916,7 @@ class NetworkSession{
|
||||
]
|
||||
);
|
||||
|
||||
$commandData[$command->getName()] = $data;
|
||||
$commandData[$command->getLabel()] = $data;
|
||||
}
|
||||
|
||||
$this->sendDataPacket(AvailableCommandsPacket::create($commandData, [], [], []));
|
||||
|
@ -30,6 +30,7 @@ use pocketmine\network\mcpe\convert\GlobalItemTypeDictionary;
|
||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||
use pocketmine\network\mcpe\InventoryManager;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\PlayerAuthInputPacket;
|
||||
use pocketmine\network\mcpe\protocol\RequestChunkRadiusPacket;
|
||||
use pocketmine\network\mcpe\protocol\StartGamePacket;
|
||||
use pocketmine\network\mcpe\protocol\types\BlockPosition;
|
||||
@ -61,6 +62,7 @@ class PreSpawnPacketHandler extends PacketHandler{
|
||||
public function setUp() : void{
|
||||
$location = $this->player->getLocation();
|
||||
|
||||
$this->session->getLogger()->debug("Preparing StartGamePacket");
|
||||
$levelSettings = new LevelSettings();
|
||||
$levelSettings->seed = -1;
|
||||
$levelSettings->spawnSettings = new SpawnSettings(SpawnSettings::BIOME_TYPE_DEFAULT, "", DimensionIds::OVERWORLD); //TODO: implement this properly
|
||||
@ -104,22 +106,41 @@ class PreSpawnPacketHandler extends PacketHandler{
|
||||
GlobalItemTypeDictionary::getInstance()->getDictionary()->getEntries(),
|
||||
));
|
||||
|
||||
$this->session->getLogger()->debug("Sending actor identifiers");
|
||||
$this->session->sendDataPacket(StaticPacketCache::getInstance()->getAvailableActorIdentifiers());
|
||||
|
||||
$this->session->getLogger()->debug("Sending biome definitions");
|
||||
$this->session->sendDataPacket(StaticPacketCache::getInstance()->getBiomeDefs());
|
||||
|
||||
$this->session->getLogger()->debug("Sending attributes");
|
||||
$this->session->syncAttributes($this->player, $this->player->getAttributeMap()->getAll());
|
||||
|
||||
$this->session->getLogger()->debug("Sending available commands");
|
||||
$this->session->syncAvailableCommands();
|
||||
|
||||
$this->session->getLogger()->debug("Sending abilities");
|
||||
$this->session->syncAbilities($this->player);
|
||||
$this->session->syncAdventureSettings();
|
||||
|
||||
$this->session->getLogger()->debug("Sending effects");
|
||||
foreach($this->player->getEffects()->all() as $effect){
|
||||
$this->session->onEntityEffectAdded($this->player, $effect, false);
|
||||
}
|
||||
|
||||
$this->session->getLogger()->debug("Sending actor metadata");
|
||||
$this->player->sendData([$this->player]);
|
||||
|
||||
$this->session->getLogger()->debug("Sending inventory");
|
||||
$this->inventoryManager->syncAll();
|
||||
$this->inventoryManager->syncCreative();
|
||||
$this->inventoryManager->syncSelectedHotbarSlot();
|
||||
|
||||
$this->session->getLogger()->debug("Sending creative inventory data");
|
||||
$this->inventoryManager->syncCreative();
|
||||
|
||||
$this->session->getLogger()->debug("Sending crafting data");
|
||||
$this->session->sendDataPacket(CraftingDataCache::getInstance()->getCache($this->server->getCraftingManager()));
|
||||
|
||||
$this->session->getLogger()->debug("Sending player list");
|
||||
$this->session->syncPlayerList($this->server->getOnlinePlayers());
|
||||
}
|
||||
|
||||
@ -128,4 +149,10 @@ class PreSpawnPacketHandler extends PacketHandler{
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handlePlayerAuthInput(PlayerAuthInputPacket $packet) : bool{
|
||||
//the client will send this every tick once we start sending chunks, but we don't handle it in this stage
|
||||
//this is very spammy so we filter it out
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,6 @@ final class RakLibThreadCrashInfo{
|
||||
return new self(null, $info["message"], $info["file"], $info["line"]);
|
||||
}
|
||||
|
||||
/** @return string|null */
|
||||
public function getClass() : ?string{ return $this->class; }
|
||||
|
||||
public function getMessage() : string{ return $this->message; }
|
||||
|
@ -418,6 +418,15 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
return $this->lastPlayed - $this->firstPlayed > 1; // microtime(true) - microtime(true) may have less than one millisecond difference
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the player is allowed to toggle flight mode.
|
||||
*
|
||||
* If set to false, the player will be locked in its current flight mode (flying/not flying), and attempts by the
|
||||
* player to enter or exit flight mode will be prevented.
|
||||
*
|
||||
* Note: Setting this to false DOES NOT change whether the player is currently flying. Use
|
||||
* {@link Player::setFlying()} for that purpose.
|
||||
*/
|
||||
public function setAllowFlight(bool $value) : void{
|
||||
if($this->allowFlight !== $value){
|
||||
$this->allowFlight = $value;
|
||||
@ -425,10 +434,24 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the player is allowed to toggle its flight state.
|
||||
*
|
||||
* If false, the player is locked in its current flight mode (flying/not flying), and attempts by the player to
|
||||
* enter or exit flight mode will be prevented.
|
||||
*/
|
||||
public function getAllowFlight() : bool{
|
||||
return $this->allowFlight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the player's movement may be obstructed by blocks with collision boxes.
|
||||
* If set to false, the player can move through any block unobstructed.
|
||||
*
|
||||
* Note: Enabling flight mode in conjunction with this is recommended. A non-flying player will simply fall through
|
||||
* the ground into the void.
|
||||
* @see Player::setFlying()
|
||||
*/
|
||||
public function setHasBlockCollision(bool $value) : void{
|
||||
if($this->blockCollision !== $value){
|
||||
$this->blockCollision = $value;
|
||||
@ -436,6 +459,10 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether blocks may obstruct the player's movement.
|
||||
* If false, the player can move through any block unobstructed.
|
||||
*/
|
||||
public function hasBlockCollision() : bool{
|
||||
return $this->blockCollision;
|
||||
}
|
||||
@ -1021,7 +1048,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
protected function internalSetGameMode(GameMode $gameMode) : void{
|
||||
$this->gamemode = $gameMode;
|
||||
|
||||
$this->allowFlight = $this->isCreative();
|
||||
$this->allowFlight = $this->gamemode->equals(GameMode::CREATIVE());
|
||||
$this->hungerManager->setEnabled($this->isSurvival());
|
||||
|
||||
if($this->isSpectator()){
|
||||
|
@ -69,6 +69,9 @@ class TaskHandler{
|
||||
return $this->nextRun;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function setNextRun(int $ticks) : void{
|
||||
$this->nextRun = $ticks;
|
||||
}
|
||||
@ -103,11 +106,17 @@ class TaskHandler{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function remove() : void{
|
||||
$this->cancelled = true;
|
||||
$this->task->setHandler(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function run() : void{
|
||||
$this->timings->startTiming();
|
||||
try{
|
||||
|
@ -195,7 +195,7 @@ class Explosion{
|
||||
}
|
||||
|
||||
$entity->attack($ev);
|
||||
$entity->setMotion($motion->multiply($impact));
|
||||
$entity->setMotion($entity->getMotion()->addVector($motion->multiply($impact)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,6 +129,11 @@ use const PHP_INT_MIN;
|
||||
|
||||
#include <rules/World.h>
|
||||
|
||||
/**
|
||||
* @phpstan-type ChunkPosHash int
|
||||
* @phpstan-type BlockPosHash int
|
||||
* @phpstan-type ChunkBlockPosHash int
|
||||
*/
|
||||
class World implements ChunkManager{
|
||||
|
||||
private static int $worldIdCounter = 1;
|
||||
@ -152,28 +157,40 @@ class World implements ChunkManager{
|
||||
|
||||
public const DEFAULT_TICKED_BLOCKS_PER_SUBCHUNK_PER_TICK = 3;
|
||||
|
||||
/** @var Player[] */
|
||||
/**
|
||||
* @var Player[] entity runtime ID => Player
|
||||
* @phpstan-var array<int, Player>
|
||||
*/
|
||||
private array $players = [];
|
||||
|
||||
/** @var Entity[] */
|
||||
/**
|
||||
* @var Entity[] entity runtime ID => Entity
|
||||
* @phpstan-var array<int, Entity>
|
||||
*/
|
||||
private array $entities = [];
|
||||
/**
|
||||
* @var Vector3[]
|
||||
* @var Vector3[] entity runtime ID => Vector3
|
||||
* @phpstan-var array<int, Vector3>
|
||||
*/
|
||||
private array $entityLastKnownPositions = [];
|
||||
|
||||
/**
|
||||
* @var Entity[][]
|
||||
* @phpstan-var array<int, array<int, Entity>>
|
||||
* @var Entity[][] chunkHash => [entity runtime ID => Entity]
|
||||
* @phpstan-var array<ChunkPosHash, array<int, Entity>>
|
||||
*/
|
||||
private array $entitiesByChunk = [];
|
||||
|
||||
/** @var Entity[] */
|
||||
/**
|
||||
* @var Entity[] entity runtime ID => Entity
|
||||
* @phpstan-var array<int, Entity>
|
||||
*/
|
||||
public $updateEntities = [];
|
||||
|
||||
private bool $inDynamicStateRecalculation = false;
|
||||
/** @var Block[][] */
|
||||
/**
|
||||
* @var Block[][] chunkHash => [relativeBlockHash => Block]
|
||||
* @phpstan-var array<ChunkPosHash, array<ChunkBlockPosHash, Block>>
|
||||
*/
|
||||
private array $blockCache = [];
|
||||
|
||||
private int $sendTimeTicker = 0;
|
||||
@ -185,22 +202,43 @@ class World implements ChunkManager{
|
||||
private int $minY;
|
||||
private int $maxY;
|
||||
|
||||
/** @var TickingChunkLoader[] */
|
||||
/**
|
||||
* @var TickingChunkLoader[] spl_object_id => TickingChunkLoader
|
||||
* @phpstan-var array<int, TickingChunkLoader>
|
||||
*/
|
||||
private array $tickingLoaders = [];
|
||||
/** @var int[] */
|
||||
/**
|
||||
* @var int[] spl_object_id => number of chunks
|
||||
* @phpstan-var array<int, int>
|
||||
*/
|
||||
private array $tickingLoaderCounter = [];
|
||||
/** @var ChunkLoader[][] */
|
||||
/**
|
||||
* @var ChunkLoader[][] chunkHash => [spl_object_id => ChunkLoader]
|
||||
* @phpstan-var array<ChunkPosHash, array<int, ChunkLoader>>
|
||||
*/
|
||||
private array $chunkLoaders = [];
|
||||
|
||||
/** @var ChunkListener[][] */
|
||||
/**
|
||||
* @var ChunkListener[][] chunkHash => [spl_object_id => ChunkListener]
|
||||
* @phpstan-var array<ChunkPosHash, array<int, ChunkListener>>
|
||||
*/
|
||||
private array $chunkListeners = [];
|
||||
/** @var Player[][] */
|
||||
/**
|
||||
* @var Player[][] chunkHash => [spl_object_id => Player]
|
||||
* @phpstan-var array<ChunkPosHash, array<int, Player>>
|
||||
*/
|
||||
private array $playerChunkListeners = [];
|
||||
|
||||
/** @var ClientboundPacket[][] */
|
||||
/**
|
||||
* @var ClientboundPacket[][]
|
||||
* @phpstan-var array<ChunkPosHash, list<ClientboundPacket>>
|
||||
*/
|
||||
private array $packetBuffersByChunk = [];
|
||||
|
||||
/** @var float[] */
|
||||
/**
|
||||
* @var float[] chunkHash => timestamp of request
|
||||
* @phpstan-var array<ChunkPosHash, float>
|
||||
*/
|
||||
private array $unloadQueue = [];
|
||||
|
||||
private int $time;
|
||||
@ -213,44 +251,65 @@ class World implements ChunkManager{
|
||||
private string $folderName;
|
||||
private string $displayName;
|
||||
|
||||
/** @var Chunk[] */
|
||||
/**
|
||||
* @var Chunk[]
|
||||
* @phpstan-var array<ChunkPosHash, Chunk>
|
||||
*/
|
||||
private array $chunks = [];
|
||||
|
||||
/** @var Vector3[][] */
|
||||
/**
|
||||
* @var Vector3[][] chunkHash => [relativeBlockHash => Vector3]
|
||||
* @phpstan-var array<ChunkPosHash, array<ChunkBlockPosHash, Vector3>>
|
||||
*/
|
||||
private array $changedBlocks = [];
|
||||
|
||||
/** @phpstan-var ReversePriorityQueue<int, Vector3> */
|
||||
private ReversePriorityQueue $scheduledBlockUpdateQueue;
|
||||
/** @var int[] */
|
||||
/**
|
||||
* @var int[] blockHash => tick delay
|
||||
* @phpstan-var array<BlockPosHash, int>
|
||||
*/
|
||||
private array $scheduledBlockUpdateQueueIndex = [];
|
||||
|
||||
/** @phpstan-var \SplQueue<int> */
|
||||
private \SplQueue $neighbourBlockUpdateQueue;
|
||||
/** @var bool[] blockhash => dummy */
|
||||
/**
|
||||
* @var true[] blockhash => dummy
|
||||
* @phpstan-var array<BlockPosHash, true>
|
||||
*/
|
||||
private array $neighbourBlockUpdateQueueIndex = [];
|
||||
|
||||
/** @var bool[] */
|
||||
/**
|
||||
* @var bool[] chunkHash => isValid
|
||||
* @phpstan-var array<ChunkPosHash, bool>
|
||||
*/
|
||||
private array $activeChunkPopulationTasks = [];
|
||||
/** @var ChunkLockId[] */
|
||||
/**
|
||||
* @var ChunkLockId[]
|
||||
* @phpstan-var array<ChunkPosHash, ChunkLockId>
|
||||
*/
|
||||
private array $chunkLock = [];
|
||||
private int $maxConcurrentChunkPopulationTasks = 2;
|
||||
/**
|
||||
* @var PromiseResolver[] chunkHash => promise
|
||||
* @phpstan-var array<int, PromiseResolver<Chunk>>
|
||||
* @phpstan-var array<ChunkPosHash, PromiseResolver<Chunk>>
|
||||
*/
|
||||
private array $chunkPopulationRequestMap = [];
|
||||
/**
|
||||
* @var \SplQueue (queue of chunkHashes)
|
||||
* @phpstan-var \SplQueue<int>
|
||||
* @phpstan-var \SplQueue<ChunkPosHash>
|
||||
*/
|
||||
private \SplQueue $chunkPopulationRequestQueue;
|
||||
/**
|
||||
* @var true[] chunkHash => dummy
|
||||
* @phpstan-var array<int, true>
|
||||
* @phpstan-var array<ChunkPosHash, true>
|
||||
*/
|
||||
private array $chunkPopulationRequestQueueIndex = [];
|
||||
|
||||
/** @var bool[] */
|
||||
/**
|
||||
* @var true[]
|
||||
* @phpstan-var array<int, true>
|
||||
*/
|
||||
private array $generatorRegisteredWorkers = [];
|
||||
|
||||
private bool $autoSave = true;
|
||||
@ -260,7 +319,10 @@ class World implements ChunkManager{
|
||||
private int $chunkTickRadius;
|
||||
private int $chunksPerTick;
|
||||
private int $tickedBlocksPerSubchunkPerTick = self::DEFAULT_TICKED_BLOCKS_PER_SUBCHUNK_PER_TICK;
|
||||
/** @var bool[] */
|
||||
/**
|
||||
* @var true[]
|
||||
* @phpstan-var array<int, true>
|
||||
*/
|
||||
private array $randomTickBlocks = [];
|
||||
|
||||
/** @var WorldTimings */
|
||||
@ -286,6 +348,9 @@ class World implements ChunkManager{
|
||||
|
||||
private \Logger $logger;
|
||||
|
||||
/**
|
||||
* @phpstan-return ChunkPosHash
|
||||
*/
|
||||
public static function chunkHash(int $x, int $z) : int{
|
||||
return morton2d_encode($x, $z);
|
||||
}
|
||||
@ -302,6 +367,9 @@ class World implements ChunkManager{
|
||||
private const BLOCKHASH_X_SHIFT = self::BLOCKHASH_Y_BITS;
|
||||
private const BLOCKHASH_Z_SHIFT = self::BLOCKHASH_X_SHIFT + self::BLOCKHASH_XZ_EXTRA_BITS;
|
||||
|
||||
/**
|
||||
* @phpstan-return BlockPosHash
|
||||
*/
|
||||
public static function blockHash(int $x, int $y, int $z) : int{
|
||||
$shiftedY = $y + self::BLOCKHASH_Y_OFFSET;
|
||||
if(($shiftedY & (~0 << self::BLOCKHASH_Y_BITS)) !== 0){
|
||||
@ -326,6 +394,9 @@ class World implements ChunkManager{
|
||||
return morton3d_encode($x, $y, $z);
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-param BlockPosHash $hash
|
||||
*/
|
||||
public static function getBlockXYZ(int $hash, ?int &$x, ?int &$y, ?int &$z) : void{
|
||||
[$baseX, $baseY, $baseZ] = morton3d_decode($hash);
|
||||
|
||||
@ -337,6 +408,9 @@ class World implements ChunkManager{
|
||||
$z = (($baseZ & self::BLOCKHASH_XZ_MASK) | $extraZ) << self::BLOCKHASH_XZ_SIGN_SHIFT >> self::BLOCKHASH_XZ_SIGN_SHIFT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-param ChunkPosHash $hash
|
||||
*/
|
||||
public static function getXZ(int $hash, ?int &$x, ?int &$z) : void{
|
||||
[$x, $z] = morton2d_decode($hash);
|
||||
}
|
||||
@ -556,6 +630,28 @@ class World implements ChunkManager{
|
||||
unset($this->unloadCallbacks[spl_object_id($callback)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of players who are in the given filter and also using the chunk containing the target position.
|
||||
* Used for broadcasting sounds and particles with specific targets.
|
||||
*
|
||||
* @param Player[] $allowed
|
||||
* @phpstan-param list<Player> $allowed
|
||||
*
|
||||
* @return array<int, Player>
|
||||
*/
|
||||
private function filterViewersForPosition(Vector3 $pos, array $allowed) : array{
|
||||
$candidates = $this->getViewersForPosition($pos);
|
||||
$filtered = [];
|
||||
foreach($allowed as $player){
|
||||
$k = spl_object_id($player);
|
||||
if(isset($candidates[$k])){
|
||||
$filtered[$k] = $candidates[$k];
|
||||
}
|
||||
}
|
||||
|
||||
return $filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Player[]|null $players
|
||||
*/
|
||||
@ -567,7 +663,7 @@ class World implements ChunkManager{
|
||||
$this->broadcastPacketToViewers($pos, $e);
|
||||
}
|
||||
}else{
|
||||
$this->server->broadcastPackets($players, $pk);
|
||||
$this->server->broadcastPackets($this->filterViewersForPosition($pos, $players), $pk);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -583,7 +679,7 @@ class World implements ChunkManager{
|
||||
$this->broadcastPacketToViewers($pos, $e);
|
||||
}
|
||||
}else{
|
||||
$this->server->broadcastPackets($players, $pk);
|
||||
$this->server->broadcastPackets($this->filterViewersForPosition($pos, $players), $pk);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -602,7 +698,8 @@ class World implements ChunkManager{
|
||||
*
|
||||
* Returns a list of players who have the target chunk within their view distance.
|
||||
*
|
||||
* @return Player[]
|
||||
* @return Player[] spl_object_id => Player
|
||||
* @phpstan-return array<int, Player>
|
||||
*/
|
||||
public function getChunkPlayers(int $chunkX, int $chunkZ) : array{
|
||||
return $this->playerChunkListeners[World::chunkHash($chunkX, $chunkZ)] ?? [];
|
||||
@ -612,6 +709,7 @@ class World implements ChunkManager{
|
||||
* Gets the chunk loaders being used in a specific chunk
|
||||
*
|
||||
* @return ChunkLoader[]
|
||||
* @phpstan-return array<int, ChunkLoader>
|
||||
*/
|
||||
public function getChunkLoaders(int $chunkX, int $chunkZ) : array{
|
||||
return $this->chunkLoaders[World::chunkHash($chunkX, $chunkZ)] ?? [];
|
||||
@ -620,7 +718,8 @@ class World implements ChunkManager{
|
||||
/**
|
||||
* Returns an array of players who have the target position within their view distance.
|
||||
*
|
||||
* @return Player[]
|
||||
* @return Player[] spl_object_id => Player
|
||||
* @phpstan-return array<int, Player>
|
||||
*/
|
||||
public function getViewersForPosition(Vector3 $pos) : array{
|
||||
return $this->getChunkPlayers($pos->getFloorX() >> Chunk::COORD_BIT_SIZE, $pos->getFloorZ() >> Chunk::COORD_BIT_SIZE);
|
||||
@ -735,6 +834,7 @@ class World implements ChunkManager{
|
||||
* Returns all the listeners attached to this chunk.
|
||||
*
|
||||
* @return ChunkListener[]
|
||||
* @phpstan-return array<int, ChunkListener>
|
||||
*/
|
||||
public function getChunkListeners(int $chunkX, int $chunkZ) : array{
|
||||
return $this->chunkListeners[World::chunkHash($chunkX, $chunkZ)] ?? [];
|
||||
@ -928,8 +1028,10 @@ class World implements ChunkManager{
|
||||
|
||||
/**
|
||||
* @param Vector3[] $blocks
|
||||
* @phpstan-param list<Vector3> $blocks
|
||||
*
|
||||
* @return ClientboundPacket[]
|
||||
* @phpstan-return list<ClientboundPacket>
|
||||
*/
|
||||
public function createBlockUpdatePackets(array $blocks) : array{
|
||||
$packets = [];
|
||||
@ -975,7 +1077,8 @@ class World implements ChunkManager{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool[] fullID => bool
|
||||
* @return true[] fullID => dummy
|
||||
* @phpstan-return array<int, true>
|
||||
*/
|
||||
public function getRandomTickedBlocks() : array{
|
||||
return $this->randomTickBlocks;
|
||||
@ -1197,6 +1300,7 @@ class World implements ChunkManager{
|
||||
|
||||
/**
|
||||
* @return Block[]
|
||||
* @phpstan-return list<Block>
|
||||
*/
|
||||
public function getCollisionBlocks(AxisAlignedBB $bb, bool $targetFirst = false) : array{
|
||||
$minX = (int) floor($bb->minX - 1);
|
||||
@ -1237,6 +1341,7 @@ class World implements ChunkManager{
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
* @phpstan-return list<AxisAlignedBB>
|
||||
*/
|
||||
public function getCollisionBoxes(Entity $entity, AxisAlignedBB $bb, bool $entities = true) : array{
|
||||
$minX = (int) floor($bb->minX - 1);
|
||||
@ -1636,6 +1741,7 @@ class World implements ChunkManager{
|
||||
* Drops XP orbs into the world for the specified amount, splitting the amount into several orbs if necessary.
|
||||
*
|
||||
* @return ExperienceOrb[]
|
||||
* @phpstan-return list<ExperienceOrb>
|
||||
*/
|
||||
public function dropExperience(Vector3 $pos, int $amount) : array{
|
||||
/** @var ExperienceOrb[] $orbs */
|
||||
@ -1888,18 +1994,24 @@ class World implements ChunkManager{
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of all the entities in this world
|
||||
* Returns a list of all the entities in this world, indexed by their entity runtime IDs
|
||||
*
|
||||
* @return Entity[]
|
||||
* @phpstan-return array<int, Entity>
|
||||
*/
|
||||
public function getEntities() : array{
|
||||
return $this->entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entities colliding the current one inside the AxisAlignedBB
|
||||
* Returns all collidable entities whose bounding boxes intersect the given bounding box.
|
||||
* If an entity is given, it will be excluded from the result.
|
||||
* If a non-collidable entity is given, the result will be empty.
|
||||
*
|
||||
* This function is the same as {@link World::getNearbyEntities()}, but with additional collidability filters.
|
||||
*
|
||||
* @return Entity[]
|
||||
* @phpstan-return array<int, Entity>
|
||||
*/
|
||||
public function getCollidingEntities(AxisAlignedBB $bb, ?Entity $entity = null) : array{
|
||||
$nearby = [];
|
||||
@ -1916,9 +2028,10 @@ class World implements ChunkManager{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entities near the current one inside the AxisAlignedBB
|
||||
* Returns all entities whose bounding boxes intersect the given bounding box, excluding the given entity.
|
||||
*
|
||||
* @return Entity[]
|
||||
* @phpstan-return array<int, Entity>
|
||||
*/
|
||||
public function getNearbyEntities(AxisAlignedBB $bb, ?Entity $entity = null) : array{
|
||||
$nearby = [];
|
||||
@ -1995,7 +2108,8 @@ class World implements ChunkManager{
|
||||
/**
|
||||
* Returns a list of the players in this world
|
||||
*
|
||||
* @return Player[]
|
||||
* @return Player[] entity runtime ID => Player
|
||||
* @phpstan-return array<int, Player>
|
||||
*/
|
||||
public function getPlayers() : array{
|
||||
return $this->players;
|
||||
@ -2042,7 +2156,8 @@ class World implements ChunkManager{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Chunk[]
|
||||
* @return Chunk[] chunkHash => Chunk
|
||||
* @phpstan-return array<ChunkPosHash, Chunk>
|
||||
*/
|
||||
public function getLoadedChunks() : array{
|
||||
return $this->chunks;
|
||||
@ -2053,7 +2168,8 @@ class World implements ChunkManager{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Entity[]
|
||||
* @return Entity[] entity runtime ID => Entity
|
||||
* @phpstan-return array<int, Entity>
|
||||
*/
|
||||
public function getChunkEntities(int $chunkX, int $chunkZ) : array{
|
||||
return $this->entitiesByChunk[World::chunkHash($chunkX, $chunkZ)] ?? [];
|
||||
@ -2069,7 +2185,8 @@ class World implements ChunkManager{
|
||||
/**
|
||||
* Returns the chunks adjacent to the specified chunk.
|
||||
*
|
||||
* @return Chunk[]|null[]
|
||||
* @return Chunk[]|null[] chunkHash => Chunk|null
|
||||
* @phpstan-return array<ChunkPosHash, Chunk|null>
|
||||
*/
|
||||
public function getAdjacentChunks(int $x, int $z) : array{
|
||||
$result = [];
|
||||
|
@ -36,6 +36,7 @@ use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\FloatMetadataProperty;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\IntMetadataProperty;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\LongMetadataProperty;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\PropertySyncData;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\StringMetadataProperty;
|
||||
|
||||
class FloatingTextParticle implements Particle{
|
||||
@ -115,6 +116,7 @@ class FloatingTextParticle implements Particle{
|
||||
0,
|
||||
[],
|
||||
$actorMetadata,
|
||||
new PropertySyncData([], []),
|
||||
[]
|
||||
);
|
||||
}
|
||||
|
35
src/world/sound/BurpSound.php
Normal file
35
src/world/sound/BurpSound.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?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\world\sound;
|
||||
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\LevelSoundEvent;
|
||||
|
||||
class BurpSound implements Sound{
|
||||
|
||||
public function encode(Vector3 $pos) : array{
|
||||
return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::BURP, $pos, false)];
|
||||
}
|
||||
}
|
@ -335,6 +335,21 @@ parameters:
|
||||
count: 3
|
||||
path: ../../../src/block/Mycelium.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/block/RedMushroom.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/block/RedMushroom.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/block/RedMushroom.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getBlockLightAt\\(\\) expects int, float\\|int given\\.$#"
|
||||
count: 1
|
||||
@ -510,11 +525,6 @@ parameters:
|
||||
count: 1
|
||||
path: ../../../src/crash/CrashDump.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$index of method pocketmine\\\\inventory\\\\BaseInventory\\:\\:setItem\\(\\) expects int, int\\|string given\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/entity/ExperienceManager.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#"
|
||||
count: 1
|
||||
|
@ -1,6 +1,6 @@
|
||||
parameters:
|
||||
ignoreErrors:
|
||||
-
|
||||
message: "#^Property pocketmine\\\\network\\\\mcpe\\\\handler\\\\StupidJsonDecodeTest\\:\\:\\$stupidJsonDecodeFunc \\(Closure\\(string, bool=\\)\\: mixed\\) does not accept Closure\\|null\\.$#"
|
||||
message: "#^Property pocketmine\\\\network\\\\mcpe\\\\handler\\\\StupidJsonDecodeTest\\:\\:\\$stupidJsonDecodeFunc \\(Closure\\(string, bool\\=\\)\\: mixed\\) does not accept Closure\\|null\\.$#"
|
||||
count: 1
|
||||
path: ../../phpunit/network/mcpe/handler/StupidJsonDecodeTest.php
|
||||
|
@ -10,16 +10,6 @@ parameters:
|
||||
count: 1
|
||||
path: ../../../src/console/ConsoleCommandSender.php
|
||||
|
||||
-
|
||||
message: "#^Method pocketmine\\\\crafting\\\\CraftingManager\\:\\:getDestructorCallbacks\\(\\) should return pocketmine\\\\utils\\\\ObjectSet\\<Closure\\(\\)\\: void\\> but returns pocketmine\\\\utils\\\\ObjectSet\\<Closure\\(\\)\\: void\\>\\|pocketmine\\\\utils\\\\ObjectSet\\<object\\>\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/crafting/CraftingManager.php
|
||||
|
||||
-
|
||||
message: "#^Property pocketmine\\\\crafting\\\\CraftingManager\\:\\:\\$destructorCallbacks \\(pocketmine\\\\utils\\\\ObjectSet\\<Closure\\(\\)\\: void\\>\\|null\\) does not accept pocketmine\\\\utils\\\\ObjectSet\\<object\\>\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/crafting/CraftingManager.php
|
||||
|
||||
-
|
||||
message: "#^Call to function assert\\(\\) with false and 'unknown hit type' will always evaluate to false\\.$#"
|
||||
count: 1
|
||||
|
Submodule tests/plugins/DevTools updated: e884a4c234...bd0fa048da
Reference in New Issue
Block a user