mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-11 20:10:17 +00:00
Compare commits
18 Commits
block-posi
...
gameplay-p
Author | SHA1 | Date | |
---|---|---|---|
a6042ec7e8 | |||
e494460cfd | |||
2c299e2b49 | |||
ac1e70cd96 | |||
0bbd4af496 | |||
b0bfc30b07 | |||
a91cef37f6 | |||
26afa97cdc | |||
57082c8148 | |||
74ee38ab99 | |||
df069b0418 | |||
ea43fd1917 | |||
ca5d9c3731 | |||
cbcc4d24e0 | |||
223fd74255 | |||
0fef4c6683 | |||
e1ae9a7d69 | |||
10a962daa2 |
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
|
||||
|
5
.github/dependabot.yml
vendored
5
.github/dependabot.yml
vendored
@ -37,7 +37,4 @@ updates:
|
||||
- package-ecosystem: github-actions
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: monthly
|
||||
groups:
|
||||
github-actions:
|
||||
patterns: ["*"]
|
||||
interval: weekly
|
||||
|
8
.github/workflows/build-docker-image.yml
vendored
8
.github/workflows/build-docker-image.yml
vendored
@ -53,7 +53,7 @@ jobs:
|
||||
run: echo NAME=$(echo "${GITHUB_REPOSITORY,,}") >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build image for tag
|
||||
uses: docker/build-push-action@v6.10.0
|
||||
uses: docker/build-push-action@v6.9.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.10.0
|
||||
uses: docker/build-push-action@v6.9.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.10.0
|
||||
uses: docker/build-push-action@v6.9.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.10.0
|
||||
uses: docker/build-push-action@v6.9.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
|
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
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +1,6 @@
|
||||
[submodule "tests/plugins/DevTools"]
|
||||
path = tests/plugins/DevTools
|
||||
url = https://github.com/pmmp/DevTools.git
|
||||
[submodule "build/php"]
|
||||
path = build/php
|
||||
url = https://github.com/pmmp/php-build-scripts.git
|
||||
|
@ -5,6 +5,7 @@ $finder = PhpCsFixer\Finder::create()
|
||||
->in(__DIR__ . '/build')
|
||||
->in(__DIR__ . '/tests')
|
||||
->in(__DIR__ . '/tools')
|
||||
->notPath('plugins/DevTools')
|
||||
->notName('PocketMine.php');
|
||||
|
||||
return (new PhpCsFixer\Config)
|
||||
|
@ -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.
|
||||
|
@ -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,116 +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.
|
@ -32,11 +32,11 @@
|
||||
"ext-zlib": ">=1.2.11",
|
||||
"composer-runtime-api": "^2.0",
|
||||
"adhocore/json-comment": "~1.2.0",
|
||||
"netresearch/jsonmapper": "~v5.0.0",
|
||||
"pocketmine/netresearch-jsonmapper": "~v4.4.999",
|
||||
"pocketmine/bedrock-block-upgrade-schema": "~5.0.0+bedrock-1.21.40",
|
||||
"pocketmine/bedrock-data": "~2.15.0+bedrock-1.21.50",
|
||||
"pocketmine/bedrock-item-upgrade-schema": "~1.14.0+bedrock-1.21.50",
|
||||
"pocketmine/bedrock-protocol": "~35.0.0+bedrock-1.21.50",
|
||||
"pocketmine/bedrock-data": "~2.14.0+bedrock-1.21.40",
|
||||
"pocketmine/bedrock-item-upgrade-schema": "~1.13.0+bedrock-1.21.40",
|
||||
"pocketmine/bedrock-protocol": "~35.0.0+bedrock-1.21.40",
|
||||
"pocketmine/binaryutils": "^0.2.1",
|
||||
"pocketmine/callback-validator": "^1.0.2",
|
||||
"pocketmine/color": "^0.3.0",
|
||||
@ -78,6 +78,7 @@
|
||||
"sort-packages": true
|
||||
},
|
||||
"scripts": {
|
||||
"make-devtools": "@php -dphar.readonly=0 tests/plugins/DevTools/src/ConsoleScript.php --make ./ --relative tests/plugins/DevTools --out plugins/DevTools.phar",
|
||||
"make-server": [
|
||||
"@composer install --no-dev --classmap-authoritative --ignore-platform-reqs",
|
||||
"@php -dphar.readonly=0 build/server-phar.php"
|
||||
|
143
composer.lock
generated
143
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": "732102eca72dc1d29e7b67dfbce07653",
|
||||
"content-hash": "c57e8f52250edfd03906219fe14fc240",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/json-comment",
|
||||
@ -125,57 +125,6 @@
|
||||
],
|
||||
"time": "2023-11-29T23:19:16+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"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-block-upgrade-schema",
|
||||
"version": "5.0.0",
|
||||
@ -204,16 +153,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-data",
|
||||
"version": "2.15.0+bedrock-1.21.50",
|
||||
"version": "2.14.1+bedrock-1.21.40",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockData.git",
|
||||
"reference": "6e819f36d781866ce63d2406be2ce7f2d1afd9ad"
|
||||
"reference": "4a41864ed09613ecec6791e2ae076a8ec7089cc4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/6e819f36d781866ce63d2406be2ce7f2d1afd9ad",
|
||||
"reference": "6e819f36d781866ce63d2406be2ce7f2d1afd9ad",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/4a41864ed09613ecec6791e2ae076a8ec7089cc4",
|
||||
"reference": "4a41864ed09613ecec6791e2ae076a8ec7089cc4",
|
||||
"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.50"
|
||||
"source": "https://github.com/pmmp/BedrockData/tree/2.14.1+bedrock-1.21.40"
|
||||
},
|
||||
"time": "2024-12-04T12:59:12+00:00"
|
||||
"time": "2024-11-12T21:36:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-item-upgrade-schema",
|
||||
"version": "1.14.0",
|
||||
"version": "1.13.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockItemUpgradeSchema.git",
|
||||
"reference": "9fc7c9bbb558a017395c1cb7dd819c033ee971bb"
|
||||
"reference": "1cf81305f2ffcf7dde9577c4f16a55c765192b03"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/9fc7c9bbb558a017395c1cb7dd819c033ee971bb",
|
||||
"reference": "9fc7c9bbb558a017395c1cb7dd819c033ee971bb",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/1cf81305f2ffcf7dde9577c4f16a55c765192b03",
|
||||
"reference": "1cf81305f2ffcf7dde9577c4f16a55c765192b03",
|
||||
"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.13.1"
|
||||
},
|
||||
"time": "2024-12-04T12:22:49+00:00"
|
||||
"time": "2024-11-12T21:33:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-protocol",
|
||||
"version": "35.0.0+bedrock-1.21.50",
|
||||
"version": "35.0.0+bedrock-1.21.40",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockProtocol.git",
|
||||
"reference": "bd1ec79bae8c88aa984e1c5f0c3313be5ae9b435"
|
||||
"reference": "6aa7cbeb4a7ec6fa58f9024aeaddad7c5c65a459"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/bd1ec79bae8c88aa984e1c5f0c3313be5ae9b435",
|
||||
"reference": "bd1ec79bae8c88aa984e1c5f0c3313be5ae9b435",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/6aa7cbeb4a7ec6fa58f9024aeaddad7c5c65a459",
|
||||
"reference": "6aa7cbeb4a7ec6fa58f9024aeaddad7c5c65a459",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -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/35.0.0+bedrock-1.21.50"
|
||||
"source": "https://github.com/pmmp/BedrockProtocol/tree/35.0.0+bedrock-1.21.40"
|
||||
},
|
||||
"time": "2024-12-04T13:02:00+00:00"
|
||||
"time": "2024-10-24T15:45:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/binaryutils",
|
||||
@ -616,6 +565,60 @@
|
||||
},
|
||||
"time": "2023-07-14T13:01:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/netresearch-jsonmapper",
|
||||
"version": "v4.4.999",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/netresearch-jsonmapper.git",
|
||||
"reference": "9a6610033d56e358e86a3e4fd5f87063c7318833"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"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",
|
||||
|
@ -10,6 +10,8 @@ includes:
|
||||
- vendor/phpstan/phpstan-strict-rules/rules.neon
|
||||
|
||||
rules:
|
||||
- pocketmine\phpstan\rules\DeprecatedLegacyEnumAccessRule
|
||||
- pocketmine\phpstan\rules\DisallowEnumComparisonRule
|
||||
- pocketmine\phpstan\rules\DisallowForeachByReferenceRule
|
||||
- pocketmine\phpstan\rules\UnsafeForeachArrayOfStringRule
|
||||
# - pocketmine\phpstan\rules\ThreadedSupportedTypesRule
|
||||
|
@ -79,7 +79,6 @@ use pocketmine\player\PlayerDataLoadException;
|
||||
use pocketmine\player\PlayerDataProvider;
|
||||
use pocketmine\player\PlayerDataSaveException;
|
||||
use pocketmine\player\PlayerInfo;
|
||||
use pocketmine\plugin\FolderPluginLoader;
|
||||
use pocketmine\plugin\PharPluginLoader;
|
||||
use pocketmine\plugin\PluginEnableOrder;
|
||||
use pocketmine\plugin\PluginGraylist;
|
||||
@ -345,10 +344,6 @@ class Server{
|
||||
return $this->maxPlayers;
|
||||
}
|
||||
|
||||
public function setMaxPlayers(int $maxPlayers) : void{
|
||||
$this->maxPlayers = $maxPlayers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the server requires that players be authenticated to Xbox Live. If true, connecting players who
|
||||
* are not logged into Xbox Live will be disconnected.
|
||||
@ -1027,7 +1022,6 @@ class Server{
|
||||
$this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool(Yml::PLUGINS_LEGACY_DATA_DIR, true) ? null : Path::join($this->dataPath, "plugin_data"), $pluginGraylist);
|
||||
$this->pluginManager->registerInterface(new PharPluginLoader($this->autoloader));
|
||||
$this->pluginManager->registerInterface(new ScriptPluginLoader());
|
||||
$this->pluginManager->registerInterface(new FolderPluginLoader($this->autoloader));
|
||||
|
||||
$providerManager = new WorldProviderManager();
|
||||
if(
|
||||
|
@ -31,7 +31,7 @@ use function str_repeat;
|
||||
|
||||
final class VersionInfo{
|
||||
public const NAME = "PocketMine-MP";
|
||||
public const BASE_VERSION = "5.23.2";
|
||||
public const BASE_VERSION = "5.21.3";
|
||||
public const IS_DEVELOPMENT_BUILD = true;
|
||||
public const BUILD_CHANNEL = "stable";
|
||||
|
||||
|
@ -116,7 +116,7 @@ class Bamboo extends Transparent{
|
||||
}
|
||||
|
||||
public function getModelPositionOffset() : ?Vector3{
|
||||
$seed = self::getOffsetSeed($this->position->x, 0, $this->position->z);
|
||||
$seed = self::getOffsetSeed($this->position->getFloorX(), 0, $this->position->getFloorZ());
|
||||
$retX = (($seed % 12) + 1) / 16;
|
||||
$retZ = ((($seed >> 8) % 12) + 1) / 16;
|
||||
return new Vector3($retX, 0, $retZ);
|
||||
@ -135,7 +135,7 @@ class Bamboo extends Transparent{
|
||||
private function seekToTop() : Bamboo{
|
||||
$world = $this->position->getWorld();
|
||||
$top = $this;
|
||||
while(($next = $world->getBlock($top->position->getSide(Facing::UP))) instanceof Bamboo && $next->hasSameTypeId($this)){
|
||||
while(($next = $world->getBlock($top->position->up())) instanceof Bamboo && $next->hasSameTypeId($this)){
|
||||
$top = $next;
|
||||
}
|
||||
return $top;
|
||||
@ -144,7 +144,7 @@ class Bamboo extends Transparent{
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item instanceof Fertilizer){
|
||||
$top = $this->seekToTop();
|
||||
if($top->grow(self::getMaxHeight($top->position->x, $top->position->z), mt_rand(1, 2), $player)){
|
||||
if($top->grow(self::getMaxHeight($top->position->getFloorX(), $top->position->getFloorZ()), mt_rand(1, 2), $player)){
|
||||
$item->pop();
|
||||
return true;
|
||||
}
|
||||
@ -159,12 +159,12 @@ class Bamboo extends Transparent{
|
||||
|
||||
private function grow(int $maxHeight, int $growAmount, ?Player $player) : bool{
|
||||
$world = $this->position->getWorld();
|
||||
if(!$world->getBlock($this->position->getSide(Facing::UP))->canBeReplaced()){
|
||||
if(!$world->getBlock($this->position->up())->canBeReplaced()){
|
||||
return false;
|
||||
}
|
||||
|
||||
$height = 1;
|
||||
while($world->getBlock($this->position->getSide(Facing::DOWN, $height))->hasSameTypeId($this)){
|
||||
while($world->getBlock($this->position->subtract(0, $height, 0))->hasSameTypeId($this)){
|
||||
if(++$height >= $maxHeight){
|
||||
return false;
|
||||
}
|
||||
@ -201,7 +201,7 @@ class Bamboo extends Transparent{
|
||||
|
||||
$tx = new BlockTransaction($world);
|
||||
foreach($newBlocks as $idx => $newBlock){
|
||||
$tx->addBlock($this->position->getSide(Facing::DOWN, $idx - $growAmount), $newBlock);
|
||||
$tx->addBlock($this->position->subtract(0, $idx - $growAmount, 0), $newBlock);
|
||||
}
|
||||
|
||||
$ev = new StructureGrowEvent($this, $tx, $player);
|
||||
@ -221,10 +221,10 @@ class Bamboo extends Transparent{
|
||||
$world = $this->position->getWorld();
|
||||
if($this->ready){
|
||||
$this->ready = false;
|
||||
if($world->getFullLight($this->position) < 9 || !$this->grow(self::getMaxHeight($this->position->x, $this->position->z), 1, null)){
|
||||
if($world->getFullLight($this->position) < 9 || !$this->grow(self::getMaxHeight($this->position->getFloorX(), $this->position->getFloorZ()), 1, null)){
|
||||
$world->setBlock($this->position, $this);
|
||||
}
|
||||
}elseif($world->getBlock($this->position->getSide(Facing::UP))->canBeReplaced()){
|
||||
}elseif($world->getBlock($this->position->up())->canBeReplaced()){
|
||||
$this->ready = true;
|
||||
$world->setBlock($this->position, $this);
|
||||
}
|
||||
|
@ -73,14 +73,14 @@ final class BambooSapling extends Flowable{
|
||||
|
||||
private function grow(?Player $player) : bool{
|
||||
$world = $this->position->getWorld();
|
||||
if(!$world->getBlock($this->position->getSide(Facing::UP))->canBeReplaced()){
|
||||
if(!$world->getBlock($this->position->up())->canBeReplaced()){
|
||||
return false;
|
||||
}
|
||||
|
||||
$tx = new BlockTransaction($world);
|
||||
$bamboo = VanillaBlocks::BAMBOO();
|
||||
$tx->addBlock($this->position, $bamboo)
|
||||
->addBlock($this->position->getSide(Facing::UP), (clone $bamboo)->setLeafSize(Bamboo::SMALL_LEAVES));
|
||||
->addBlock($this->position->up(), (clone $bamboo)->setLeafSize(Bamboo::SMALL_LEAVES));
|
||||
|
||||
$ev = new StructureGrowEvent($this, $tx, $player);
|
||||
$ev->call();
|
||||
@ -102,7 +102,7 @@ final class BambooSapling extends Flowable{
|
||||
if($world->getFullLight($this->position) < 9 || !$this->grow(null)){
|
||||
$world->setBlock($this->position, $this);
|
||||
}
|
||||
}elseif($world->getBlock($this->position->getSide(Facing::UP))->canBeReplaced()){
|
||||
}elseif($world->getBlock($this->position->up())->canBeReplaced()){
|
||||
$this->ready = true;
|
||||
$world->setBlock($this->position, $this);
|
||||
}
|
||||
|
@ -99,10 +99,10 @@ abstract class BaseBigDripleaf extends Transparent{
|
||||
return false;
|
||||
}
|
||||
$pos = $head->position;
|
||||
$up = $pos->getSide(Facing::UP);
|
||||
$up = $pos->up();
|
||||
$world = $pos->getWorld();
|
||||
if(
|
||||
!$world->isInWorld($up->x, $up->y, $up->z) ||
|
||||
!$world->isInWorld($up->getFloorX(), $up->getFloorY(), $up->getFloorZ()) ||
|
||||
$world->getBlock($up)->getTypeId() !== BlockTypeIds::AIR
|
||||
){
|
||||
return false;
|
||||
|
@ -27,7 +27,6 @@ use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\CoralTypeTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use function mt_rand;
|
||||
|
||||
abstract class BaseCoral extends Transparent{
|
||||
@ -56,9 +55,11 @@ abstract class BaseCoral extends Transparent{
|
||||
public function isSolid() : bool{ return false; }
|
||||
|
||||
protected function isCoveredWithWater() : bool{
|
||||
$world = $this->position->getWorld();
|
||||
|
||||
$hasWater = false;
|
||||
foreach(Facing::ALL as $side){
|
||||
if($this->getSide($side) instanceof Water){
|
||||
foreach($this->position->sides() as $vector3){
|
||||
if($world->getBlock($vector3) instanceof Water){
|
||||
$hasWater = true;
|
||||
break;
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ abstract class BaseSign extends Transparent{
|
||||
|
||||
private function changeSignGlowingState(bool $glowing, Player $player, Item $item) : bool{
|
||||
if($this->text->isGlowing() !== $glowing && $this->doSignChange(new SignText($this->text->getLines(), $this->text->getBaseColor(), $glowing), $player, $item)){
|
||||
$this->position->getWorld()->addSound($this->position->center(), new InkSacUseSound());
|
||||
$this->position->getWorld()->addSound($this->position, new InkSacUseSound());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -183,7 +183,7 @@ abstract class BaseSign extends Transparent{
|
||||
$color->toARGB() !== $this->text->getBaseColor()->toARGB() &&
|
||||
$this->doSignChange(new SignText($this->text->getLines(), $color, $this->text->isGlowing()), $player, $item)
|
||||
){
|
||||
$this->position->getWorld()->addSound($this->position->center(), new DyeUseSound());
|
||||
$this->position->getWorld()->addSound($this->position, new DyeUseSound());
|
||||
return true;
|
||||
}
|
||||
}elseif(match($item->getTypeId()){
|
||||
|
@ -128,7 +128,7 @@ class Bed extends Transparent{
|
||||
$player->sendMessage(TextFormat::GRAY . "This bed is incomplete");
|
||||
|
||||
return true;
|
||||
}elseif($playerPos->distanceSquared($this->position->center()) > 4 && $playerPos->distanceSquared($other->position->center()) > 4){
|
||||
}elseif($playerPos->distanceSquared($this->position) > 4 && $playerPos->distanceSquared($other->position) > 4){
|
||||
$player->sendMessage(KnownTranslationFactory::tile_bed_tooFar()->prefix(TextFormat::GRAY));
|
||||
return true;
|
||||
}
|
||||
|
@ -143,10 +143,10 @@ final class Bell extends Transparent{
|
||||
|
||||
public function ring(int $faceHit) : void{
|
||||
$world = $this->position->getWorld();
|
||||
$world->addSound($this->position->center(), new BellRingSound());
|
||||
$world->addSound($this->position, new BellRingSound());
|
||||
$tile = $world->getTile($this->position);
|
||||
if($tile instanceof TileBell){
|
||||
$world->broadcastPacketOnBlock($this->position, $tile->createFakeUpdatePacket($faceHit));
|
||||
$world->broadcastPacketToViewers($this->position, $tile->createFakeUpdatePacket($faceHit));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ class BigDripleafHead extends BaseBigDripleaf{
|
||||
public function onProjectileHit(Projectile $projectile, RayTraceResult $hitResult) : void{
|
||||
if($this->leafState !== DripleafState::FULL_TILT){
|
||||
$this->setTiltAndScheduleTick(DripleafState::FULL_TILT);
|
||||
$this->position->getWorld()->addSound($this->position->center(), new DripleafTiltDownSound());
|
||||
$this->position->getWorld()->addSound($this->position, new DripleafTiltDownSound());
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,13 +101,13 @@ class BigDripleafHead extends BaseBigDripleaf{
|
||||
if($this->leafState !== DripleafState::STABLE){
|
||||
if($this->leafState === DripleafState::FULL_TILT){
|
||||
$this->position->getWorld()->setBlock($this->position, $this->setLeafState(DripleafState::STABLE));
|
||||
$this->position->getWorld()->addSound($this->position->center(), new DripleafTiltUpSound());
|
||||
$this->position->getWorld()->addSound($this->position, new DripleafTiltUpSound());
|
||||
}else{
|
||||
$this->setTiltAndScheduleTick(match($this->leafState){
|
||||
DripleafState::UNSTABLE => DripleafState::PARTIAL_TILT,
|
||||
DripleafState::PARTIAL_TILT => DripleafState::FULL_TILT,
|
||||
});
|
||||
$this->position->getWorld()->addSound($this->position->center(), new DripleafTiltDownSound());
|
||||
$this->position->getWorld()->addSound($this->position, new DripleafTiltDownSound());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ class Block{
|
||||
protected BlockIdentifier $idInfo;
|
||||
protected string $fallbackName;
|
||||
protected BlockTypeInfo $typeInfo;
|
||||
protected BlockPosition $position;
|
||||
protected Position $position;
|
||||
|
||||
/** @var AxisAlignedBB[]|null */
|
||||
protected ?array $collisionBoxes = null;
|
||||
@ -107,7 +107,7 @@ class Block{
|
||||
$this->idInfo = $idInfo;
|
||||
$this->fallbackName = $name;
|
||||
$this->typeInfo = $typeInfo;
|
||||
$this->position = new BlockPosition(0, 0, 0, null);
|
||||
$this->position = new Position(0, 0, 0, null);
|
||||
|
||||
$calculator = new RuntimeDataSizeCalculator();
|
||||
$this->describeBlockItemState($calculator);
|
||||
@ -377,7 +377,7 @@ class Block{
|
||||
*/
|
||||
public function writeStateToWorld() : void{
|
||||
$world = $this->position->getWorld();
|
||||
$chunk = $world->loadChunk($this->position->x >> Chunk::COORD_BIT_SIZE, $this->position->z >> Chunk::COORD_BIT_SIZE);
|
||||
$chunk = $world->getOrLoadChunkAtPosition($this->position);
|
||||
if($chunk === null){
|
||||
throw new AssumptionFailedError("World::setBlock() should have loaded the chunk before calling this method");
|
||||
}
|
||||
@ -398,7 +398,7 @@ class Block{
|
||||
* @var Tile $tile
|
||||
* @see Tile::__construct()
|
||||
*/
|
||||
$tile = new $tileType($this->position);
|
||||
$tile = new $tileType($world, $this->position->asVector3());
|
||||
$world->addTile($tile);
|
||||
}
|
||||
}
|
||||
@ -608,7 +608,7 @@ class Block{
|
||||
return false;
|
||||
}
|
||||
|
||||
final public function getPosition() : BlockPosition{
|
||||
final public function getPosition() : Position{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
@ -616,7 +616,7 @@ class Block{
|
||||
* @internal
|
||||
*/
|
||||
final public function position(World $world, int $x, int $y, int $z) : void{
|
||||
$this->position = new BlockPosition($x, $y, $z, $world);
|
||||
$this->position = new Position($x, $y, $z, $world);
|
||||
$this->collisionBoxes = null;
|
||||
}
|
||||
|
||||
@ -912,9 +912,9 @@ class Block{
|
||||
if($this->collisionBoxes === null){
|
||||
$this->collisionBoxes = $this->recalculateCollisionBoxes();
|
||||
$extraOffset = $this->getModelPositionOffset();
|
||||
[$dx, $dy, $dz] = $extraOffset !== null ? [$extraOffset->x, $extraOffset->y, $extraOffset->z] : [0, 0, 0];
|
||||
$offset = $extraOffset !== null ? $this->position->addVector($extraOffset) : $this->position;
|
||||
foreach($this->collisionBoxes as $bb){
|
||||
$bb->offset($this->position->x + $dx, $this->position->y + $dy, $this->position->z + $dz);
|
||||
$bb->offset($offset->x, $offset->y, $offset->z);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,110 +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\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\world\World;
|
||||
use function iterator_to_array;
|
||||
|
||||
final class BlockPosition implements \Stringable{
|
||||
|
||||
public function __construct(
|
||||
public readonly int $x,
|
||||
public readonly int $y,
|
||||
public readonly int $z,
|
||||
private ?World $world //TODO: make this non-nullable (requires Blocks not to reference positions)
|
||||
){}
|
||||
|
||||
/**
|
||||
* Returns the position's world if valid. Throws an error if the world is unexpectedly invalid.
|
||||
*
|
||||
* @throws AssumptionFailedError
|
||||
*/
|
||||
public function getWorld() : World{
|
||||
if($this->world === null || !$this->world->isLoaded()){
|
||||
throw new AssumptionFailedError("Position world is null or has been unloaded");
|
||||
}
|
||||
|
||||
return $this->world;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this object has a valid reference to a loaded world
|
||||
*/
|
||||
public function isValid() : bool{
|
||||
if($this->world !== null && !$this->world->isLoaded()){
|
||||
$this->world = null;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->world !== null;
|
||||
}
|
||||
|
||||
public function asVector3() : Vector3{
|
||||
return new Vector3($this->x, $this->y, $this->z);
|
||||
}
|
||||
|
||||
public function center() : Vector3{
|
||||
return new Vector3($this->x + 0.5, $this->y + 0.5, $this->z + 0.5);
|
||||
}
|
||||
|
||||
public static function fromVector3(Vector3 $vector3, World $world) : self{
|
||||
return new self($vector3->getFloorX(), $vector3->getFloorY(), $vector3->getFloorZ(), $world);
|
||||
}
|
||||
|
||||
public function getSide(int $side, int $step = 1) : BlockPosition{
|
||||
$offset = Facing::OFFSET[$side] ?? throw new \InvalidArgumentException("Invalid side $side");
|
||||
|
||||
[$dx, $dy, $dz] = $offset;
|
||||
return new BlockPosition($this->x + ($dx * $step), $this->y + ($dy * $step), $this->z + ($dz * $step), $this->world);
|
||||
}
|
||||
|
||||
public function add(int $x, int $y, int $z) : BlockPosition{
|
||||
return new BlockPosition($this->x + $x, $this->y + $y, $this->z + $z, $this->world);
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-return \Generator<int, self, void, void>
|
||||
*/
|
||||
public function getAllSides() : \Generator{
|
||||
foreach(Facing::ALL as $facing){
|
||||
yield $this->getSide($facing);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-return list<self>
|
||||
*/
|
||||
public function getAllSidesArray() : array{
|
||||
return iterator_to_array($this->getAllSides(), preserve_keys: false);
|
||||
}
|
||||
|
||||
public function __toString() : string{
|
||||
$worldName = $this->world?->getFolderName() ?? "???";
|
||||
return "BlockPosition(x=$this->x,y=$this->y,z=$this->z,world={$worldName}";
|
||||
}
|
||||
}
|
@ -67,7 +67,7 @@ abstract class Button extends Flowable{
|
||||
$world = $this->position->getWorld();
|
||||
$world->setBlock($this->position, $this);
|
||||
$world->scheduleDelayedBlockUpdate($this->position, $this->getActivationTime());
|
||||
$world->addSound($this->position->center(), new RedstonePowerOnSound());
|
||||
$world->addSound($this->position->add(0.5, 0.5, 0.5), new RedstonePowerOnSound());
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -78,7 +78,7 @@ abstract class Button extends Flowable{
|
||||
$this->pressed = false;
|
||||
$world = $this->position->getWorld();
|
||||
$world->setBlock($this->position, $this);
|
||||
$world->addSound($this->position->center(), new RedstonePowerOffSound());
|
||||
$world->addSound($this->position->add(0.5, 0.5, 0.5), new RedstonePowerOffSound());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,6 +76,6 @@ class CakeWithCandle extends BaseCake{
|
||||
|
||||
public function onConsume(Living $consumer) : void{
|
||||
parent::onConsume($consumer);
|
||||
$this->position->getWorld()->dropItem($this->position->center(), $this->getCandle()->asItem());
|
||||
$this->position->getWorld()->dropItem($this->position->add(0.5, 0.5, 0.5), $this->getCandle()->asItem());
|
||||
}
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ class Campfire extends Transparent{
|
||||
if($item->getTypeId() === ItemTypeIds::FIRE_CHARGE){
|
||||
$item->pop();
|
||||
$this->ignite();
|
||||
$this->position->getWorld()->addSound($this->position->center(), new BlazeShootSound());
|
||||
$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){
|
||||
@ -205,7 +205,7 @@ class Campfire extends Transparent{
|
||||
$ingredient->setCount(1);
|
||||
if(count($this->inventory->addItem($ingredient)) === 0){
|
||||
$item->pop();
|
||||
$this->position->getWorld()->addSound($this->position->center(), new ItemFrameAddItemSound());
|
||||
$this->position->getWorld()->addSound($this->position, new ItemFrameAddItemSound());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -259,26 +259,26 @@ class Campfire extends Transparent{
|
||||
|
||||
$this->inventory->setItem($slot, VanillaItems::AIR());
|
||||
$this->setCookingTime($slot, 0);
|
||||
$this->position->getWorld()->dropItem($this->position->asVector3()->add(0.5, 1, 0.5), $ev->getResult());
|
||||
$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->center(), $furnaceType->getCookSound());
|
||||
$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->center(), new FireExtinguishSound());
|
||||
$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->center(), new FlintSteelSound());
|
||||
$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);
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ final class Cauldron extends Transparent{
|
||||
*/
|
||||
private function fill(int $amount, FillableCauldron $result, Item $usedItem, Item $returnedItem, array &$returnedItems) : void{
|
||||
$this->position->getWorld()->setBlock($this->position, $result->setFillLevel($amount));
|
||||
$this->position->getWorld()->addSound($this->position->center(), $result->getFillSound());
|
||||
$this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), $result->getFillSound());
|
||||
|
||||
$usedItem->pop();
|
||||
$returnedItems[] = $returnedItem;
|
||||
@ -95,10 +95,10 @@ final class Cauldron extends Transparent{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
$world = $this->position->getWorld();
|
||||
if($this->getSide(Facing::UP)->getTypeId() === BlockTypeIds::WATER){
|
||||
if($world->getBlock($this->position->up())->getTypeId() === BlockTypeIds::WATER){
|
||||
$cauldron = VanillaBlocks::WATER_CAULDRON()->setFillLevel(FillableCauldron::MAX_FILL_LEVEL);
|
||||
$world->setBlock($this->position, $cauldron);
|
||||
$world->addSound($this->position->center(), $cauldron->getFillSound());
|
||||
$world->addSound($this->position->add(0.5, 0.5, 0.5), $cauldron->getFillSound());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -90,8 +90,8 @@ class CaveVines extends Flowable{
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($this->berries){
|
||||
$this->position->getWorld()->dropItem($this->position->center(), $this->asItem());
|
||||
$this->position->getWorld()->addSound($this->position->center(), new GlowBerriesPickSound());
|
||||
$this->position->getWorld()->dropItem($this->position, $this->asItem());
|
||||
$this->position->getWorld()->addSound($this->position, new GlowBerriesPickSound());
|
||||
|
||||
$this->position->getWorld()->setBlock($this->position, $this->setBerries(false));
|
||||
return true;
|
||||
@ -117,7 +117,7 @@ class CaveVines extends Flowable{
|
||||
if($this->age < self::MAX_AGE && mt_rand(1, 10) === 1){
|
||||
$growthPos = $this->position->getSide(Facing::DOWN);
|
||||
$world = $growthPos->getWorld();
|
||||
if($world->isInWorld($growthPos->x, $growthPos->y, $growthPos->z)){
|
||||
if($world->isInWorld($growthPos->getFloorX(), $growthPos->getFloorY(), $growthPos->getFloorZ())){
|
||||
$block = $world->getBlock($growthPos);
|
||||
if($block->getTypeId() === BlockTypeIds::AIR){
|
||||
$newState = VanillaBlocks::CAVE_VINES()
|
||||
|
@ -27,12 +27,15 @@ use pocketmine\block\utils\AgeableTrait;
|
||||
use pocketmine\block\utils\StaticSupportTrait;
|
||||
use pocketmine\entity\projectile\Projectile;
|
||||
use pocketmine\event\block\StructureGrowEvent;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\RayTraceResult;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\sound\ChorusFlowerDieSound;
|
||||
use pocketmine\world\sound\ChorusFlowerGrowSound;
|
||||
use pocketmine\world\World;
|
||||
use function array_rand;
|
||||
use function min;
|
||||
use function mt_rand;
|
||||
@ -51,22 +54,24 @@ final class ChorusFlower extends Flowable{
|
||||
}
|
||||
|
||||
private function canBeSupportedAt(Block $block) : bool{
|
||||
$down = $block->getSide(Facing::DOWN);
|
||||
$position = $block->position;
|
||||
$world = $position->getWorld();
|
||||
$down = $world->getBlock($position->down());
|
||||
|
||||
if($down->getTypeId() === BlockTypeIds::END_STONE || $down->getTypeId() === BlockTypeIds::CHORUS_PLANT){
|
||||
return true;
|
||||
}
|
||||
|
||||
$plantAdjacent = false;
|
||||
foreach(Facing::HORIZONTAL as $side){
|
||||
$sideBlock = $block->getSide($side);
|
||||
foreach($position->sidesAroundAxis(Axis::Y) as $sidePosition){
|
||||
$block = $world->getBlock($sidePosition);
|
||||
|
||||
if($sideBlock->getTypeId() === BlockTypeIds::CHORUS_PLANT){
|
||||
if($block->getTypeId() === BlockTypeIds::CHORUS_PLANT){
|
||||
if($plantAdjacent){ //at most one plant may be horizontally adjacent
|
||||
return false;
|
||||
}
|
||||
$plantAdjacent = true;
|
||||
}elseif($sideBlock->getTypeId() !== BlockTypeIds::AIR){
|
||||
}elseif($block->getTypeId() !== BlockTypeIds::AIR){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -87,7 +92,7 @@ final class ChorusFlower extends Flowable{
|
||||
$stemHeight = 0;
|
||||
$endStoneBelow = false;
|
||||
for($yOffset = 0; $yOffset < self::MAX_STEM_HEIGHT; $yOffset++, $stemHeight++){
|
||||
$down = $this->getSide(Facing::DOWN, $yOffset + 1);
|
||||
$down = $world->getBlock($this->position->down($yOffset + 1));
|
||||
|
||||
if($down->getTypeId() !== BlockTypeIds::CHORUS_PLANT){
|
||||
if($down->getTypeId() === BlockTypeIds::END_STONE){
|
||||
@ -100,13 +105,12 @@ final class ChorusFlower extends Flowable{
|
||||
return [$stemHeight, $endStoneBelow];
|
||||
}
|
||||
|
||||
private function allHorizontalBlocksEmpty(BlockPosition $position, ?int $except) : bool{
|
||||
$world = $position->getWorld();
|
||||
foreach(Facing::HORIZONTAL as $facing){
|
||||
private function allHorizontalBlocksEmpty(World $world, Vector3 $position, ?int $except) : bool{
|
||||
foreach($position->sidesAroundAxis(Axis::Y) as $facing => $sidePosition){
|
||||
if($facing === $except){
|
||||
continue;
|
||||
}
|
||||
if($world->getBlock($position->getSide($facing))->getTypeId() !== BlockTypeIds::AIR){
|
||||
if($world->getBlock($sidePosition)->getTypeId() !== BlockTypeIds::AIR){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -117,7 +121,7 @@ final class ChorusFlower extends Flowable{
|
||||
private function canGrowUpwards(int $stemHeight, bool $endStoneBelow) : bool{
|
||||
$world = $this->position->getWorld();
|
||||
|
||||
$up = $this->position->getSide(Facing::UP);
|
||||
$up = $this->position->up();
|
||||
if(
|
||||
//the space above must be empty and writable
|
||||
!$world->isInWorld($up->x, $up->y, $up->z) ||
|
||||
@ -125,7 +129,7 @@ final class ChorusFlower extends Flowable{
|
||||
(
|
||||
//the space above that must be empty, but doesn't need to be writable
|
||||
$world->isInWorld($up->x, $up->y + 1, $up->z) &&
|
||||
$world->getBlock($up->getSide(Facing::UP))->getTypeId() !== BlockTypeIds::AIR
|
||||
$world->getBlock($up->up())->getTypeId() !== BlockTypeIds::AIR
|
||||
)
|
||||
){
|
||||
return false;
|
||||
@ -141,7 +145,7 @@ final class ChorusFlower extends Flowable{
|
||||
}
|
||||
}
|
||||
|
||||
return $this->allHorizontalBlocksEmpty($up, null);
|
||||
return $this->allHorizontalBlocksEmpty($world, $up, null);
|
||||
}
|
||||
|
||||
private function grow(int $facing, int $ageChange, ?BlockTransaction $tx) : BlockTransaction{
|
||||
@ -179,8 +183,8 @@ final class ChorusFlower extends Flowable{
|
||||
$sidePosition = $this->position->getSide($facing);
|
||||
if(
|
||||
$world->getBlock($sidePosition)->getTypeId() === BlockTypeIds::AIR &&
|
||||
$world->getBlock($sidePosition->getSide(Facing::DOWN))->getTypeId() === BlockTypeIds::AIR &&
|
||||
$this->allHorizontalBlocksEmpty($sidePosition, Facing::opposite($facing))
|
||||
$world->getBlock($sidePosition->down())->getTypeId() === BlockTypeIds::AIR &&
|
||||
$this->allHorizontalBlocksEmpty($world, $sidePosition, Facing::opposite($facing))
|
||||
){
|
||||
$tx = $this->grow($facing, 1, $tx);
|
||||
}
|
||||
@ -192,10 +196,10 @@ final class ChorusFlower extends Flowable{
|
||||
$ev = new StructureGrowEvent($this, $tx, null);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled() && $tx->apply()){
|
||||
$world->addSound($this->position->center(), new ChorusFlowerGrowSound());
|
||||
$world->addSound($this->position->add(0.5, 0.5, 0.5), new ChorusFlowerGrowSound());
|
||||
}
|
||||
}else{
|
||||
$world->addSound($this->position->center(), new ChorusFlowerDieSound());
|
||||
$world->addSound($this->position->add(0.5, 0.5, 0.5), new ChorusFlowerDieSound());
|
||||
$this->position->getWorld()->setBlock($this->position, $this->setAge(self::MAX_AGE));
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ namespace pocketmine\block;
|
||||
use pocketmine\block\utils\StaticSupportTrait;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use function mt_rand;
|
||||
@ -50,18 +51,21 @@ final class ChorusPlant extends Flowable{
|
||||
}
|
||||
|
||||
private function canBeSupportedAt(Block $block) : bool{
|
||||
$down = $block->getSide(Facing::DOWN);
|
||||
$verticalAir = $down->getTypeId() === BlockTypeIds::AIR || $block->getSide(Facing::UP)->getTypeId() === BlockTypeIds::AIR;
|
||||
$position = $block->position;
|
||||
$world = $position->getWorld();
|
||||
|
||||
foreach(Facing::HORIZONTAL as $facing){
|
||||
$sideBlock = $block->getSide($facing);
|
||||
$down = $world->getBlock($position->down());
|
||||
$verticalAir = $down->getTypeId() === BlockTypeIds::AIR || $world->getBlock($position->up())->getTypeId() === BlockTypeIds::AIR;
|
||||
|
||||
if($sideBlock->getTypeId() === BlockTypeIds::CHORUS_PLANT){
|
||||
foreach($position->sidesAroundAxis(Axis::Y) as $sidePosition){
|
||||
$block = $world->getBlock($sidePosition);
|
||||
|
||||
if($block->getTypeId() === BlockTypeIds::CHORUS_PLANT){
|
||||
if(!$verticalAir){
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->canBeSupportedBy($sideBlock->getSide(Facing::DOWN))){
|
||||
if($this->canBeSupportedBy($block->getSide(Facing::DOWN))){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ namespace pocketmine\block;
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\CoralTypeTrait;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use function mt_rand;
|
||||
|
||||
final class CoralBlock extends Opaque{
|
||||
@ -40,9 +39,11 @@ final class CoralBlock extends Opaque{
|
||||
|
||||
public function onScheduledUpdate() : void{
|
||||
if(!$this->dead){
|
||||
$world = $this->position->getWorld();
|
||||
|
||||
$hasWater = false;
|
||||
foreach(Facing::ALL as $facing){
|
||||
if($this->getSide($facing) instanceof Water){
|
||||
foreach($this->position->sides() as $vector3){
|
||||
if($world->getBlock($vector3) instanceof Water){
|
||||
$hasWater = true;
|
||||
break;
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ class Dirt extends Opaque{
|
||||
$item->applyDamage(1);
|
||||
|
||||
$newBlock = $this->dirtType === DirtType::NORMAL ? VanillaBlocks::FARMLAND() : VanillaBlocks::DIRT();
|
||||
$center = $this->position->center();
|
||||
$center = $this->position->add(0.5, 0.5, 0.5);
|
||||
$world->addSound($center, new ItemUseOnBlockSound($newBlock));
|
||||
$world->setBlock($this->position, $newBlock);
|
||||
if($this->dirtType === DirtType::ROOTED){
|
||||
@ -83,7 +83,7 @@ class Dirt extends Opaque{
|
||||
}elseif(($item instanceof Potion || $item instanceof SplashPotion) && $item->getType() === PotionType::WATER){
|
||||
$item->pop();
|
||||
$world->setBlock($this->position, VanillaBlocks::MUD());
|
||||
$world->addSound($this->position->center(), new WaterSplashSound(0.5));
|
||||
$world->addSound($this->position, new WaterSplashSound(0.5));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ class Door extends Transparent{
|
||||
}
|
||||
|
||||
$world->setBlock($this->position, $this);
|
||||
$world->addSound($this->position->center(), new DoorSound());
|
||||
$world->addSound($this->position, new DoorSound());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\event\block\BlockTeleportEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\GameMode;
|
||||
use pocketmine\permission\DefaultPermissionNames;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\particle\DragonEggTeleportParticle;
|
||||
use pocketmine\world\World;
|
||||
@ -50,7 +50,7 @@ class DragonEgg extends Transparent implements Fallable{
|
||||
}
|
||||
|
||||
public function onAttack(Item $item, int $face, ?Player $player = null) : bool{
|
||||
if($player !== null && $player->getGamemode() !== GameMode::CREATIVE){
|
||||
if($player !== null && !$player->hasPermission(DefaultPermissionNames::GAME_BLOCK_DELETE)){
|
||||
$this->teleport();
|
||||
return true;
|
||||
}
|
||||
@ -66,17 +66,16 @@ class DragonEgg extends Transparent implements Fallable{
|
||||
$this->position->z + mt_rand(-16, 16)
|
||||
);
|
||||
if($block instanceof Air){
|
||||
//TODO: this needs migrating to BlockPosition, but having World in there presents some issues
|
||||
$ev = new BlockTeleportEvent($this, $block->position->asVector3());
|
||||
$ev = new BlockTeleportEvent($this, $block->position);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
break;
|
||||
}
|
||||
|
||||
$blockPos = $ev->getTo();
|
||||
$world->addParticle($this->position->center(), new DragonEggTeleportParticle($this->position->x - $blockPos->getFloorX(), $this->position->y - $blockPos->getFloorY(), $this->position->z - $blockPos->getFloorZ()));
|
||||
$world->addParticle($this->position, new DragonEggTeleportParticle($this->position->x - $blockPos->x, $this->position->y - $blockPos->y, $this->position->z - $blockPos->z));
|
||||
$world->setBlock($this->position, VanillaBlocks::AIR());
|
||||
$world->setBlockAt($blockPos->getFloorX(), $blockPos->getFloorY(), $blockPos->getFloorZ(), $this);
|
||||
$world->setBlock($blockPos, $this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -161,9 +161,9 @@ class Farmland extends Transparent{
|
||||
protected function canHydrate() : bool{
|
||||
$world = $this->position->getWorld();
|
||||
|
||||
$startX = $this->position->x - (int) (self::WATER_SEARCH_HORIZONTAL_LENGTH / 2);
|
||||
$startY = $this->position->y;
|
||||
$startZ = $this->position->z - (int) (self::WATER_SEARCH_HORIZONTAL_LENGTH / 2);
|
||||
$startX = $this->position->getFloorX() - (int) (self::WATER_SEARCH_HORIZONTAL_LENGTH / 2);
|
||||
$startY = $this->position->getFloorY();
|
||||
$startZ = $this->position->getFloorZ() - (int) (self::WATER_SEARCH_HORIZONTAL_LENGTH / 2);
|
||||
|
||||
if($this->waterPositionIndex !== self::WATER_POSITION_INDEX_UNKNOWN){
|
||||
$raw = $this->waterPositionIndex;
|
||||
|
@ -111,7 +111,7 @@ class FenceGate extends Transparent{
|
||||
|
||||
$world = $this->position->getWorld();
|
||||
$world->setBlock($this->position, $this);
|
||||
$world->addSound($this->position->center(), new DoorSound());
|
||||
$world->addSound($this->position, new DoorSound());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ abstract class FillableCauldron extends Transparent{
|
||||
return;
|
||||
}
|
||||
$this->position->getWorld()->setBlock($this->position, $this->withFillLevel($this->fillLevel + $amount));
|
||||
$this->position->getWorld()->addSound($this->position->center(), $this->getFillSound());
|
||||
$this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), $this->getFillSound());
|
||||
|
||||
$usedItem->pop();
|
||||
$returnedItems[] = $returnedItem;
|
||||
@ -94,7 +94,7 @@ abstract class FillableCauldron extends Transparent{
|
||||
}
|
||||
|
||||
$this->position->getWorld()->setBlock($this->position, $this->withFillLevel($this->fillLevel - $amount));
|
||||
$this->position->getWorld()->addSound($this->position->center(), $this->getEmptySound());
|
||||
$this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), $this->getEmptySound());
|
||||
|
||||
$usedItem->pop();
|
||||
$returnedItems[] = $returnedItem;
|
||||
|
@ -161,7 +161,7 @@ class Fire extends BaseFire{
|
||||
$ageDivisor = $this->age + 30;
|
||||
|
||||
for($y = -1; $y <= 4; ++$y){
|
||||
$targetY = $y + $this->position->y;
|
||||
$targetY = $y + (int) $this->position->y;
|
||||
if($targetY < World::Y_MIN || $targetY >= World::Y_MAX){
|
||||
continue;
|
||||
}
|
||||
@ -169,12 +169,12 @@ class Fire extends BaseFire{
|
||||
$randomBound = 100 + ($y > 1 ? ($y - 1) * 100 : 0);
|
||||
|
||||
for($z = -1; $z <= 1; ++$z){
|
||||
$targetZ = $z + $this->position->z;
|
||||
$targetZ = $z + (int) $this->position->z;
|
||||
for($x = -1; $x <= 1; ++$x){
|
||||
if($x === 0 && $y === 0 && $z === 0){
|
||||
continue;
|
||||
}
|
||||
$targetX = $x + $this->position->x;
|
||||
$targetX = $x + (int) $this->position->x;
|
||||
if(!$world->isInWorld($targetX, $targetY, $targetZ)){
|
||||
continue;
|
||||
}
|
||||
@ -190,10 +190,9 @@ class Fire extends BaseFire{
|
||||
//TODO: fire can't spread if it's raining in any horizontally adjacent block, or the current one
|
||||
|
||||
$encouragement = 0;
|
||||
foreach(Facing::ALL as $facing){
|
||||
$sidePos = $block->position->getSide($facing);
|
||||
if($world->isInWorld($sidePos->x, $sidePos->y, $sidePos->z)){
|
||||
$encouragement = max($encouragement, $world->getBlockAt($sidePos->x, $sidePos->y, $sidePos->z)->getFlameEncouragement());
|
||||
foreach($block->position->sides() as $vector3){
|
||||
if($world->isInWorld($vector3->x, $vector3->y, $vector3->z)){
|
||||
$encouragement = max($encouragement, $world->getBlockAt($vector3->x, $vector3->y, $vector3->z)->getFlameEncouragement());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ final class FloorCoralFan extends BaseCoral{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($player !== null){
|
||||
$playerBlockPos = $player->getPosition()->floor();
|
||||
$directionVector = $blockReplace->position->asVector3()->subtractVector($playerBlockPos)->normalize();
|
||||
$directionVector = $blockReplace->position->subtractVector($playerBlockPos)->normalize();
|
||||
$angle = rad2deg(atan2($directionVector->getZ(), $directionVector->getX()));
|
||||
|
||||
if($angle <= 45 || 315 <= $angle || (135 <= $angle && $angle <= 225)){
|
||||
|
@ -111,7 +111,7 @@ class FlowerPot extends Flowable{
|
||||
$removedItems = $player->getInventory()->addItem(...$removedItems);
|
||||
}
|
||||
foreach($removedItems as $drops){
|
||||
$world->dropItem($this->position->center(), $drops);
|
||||
$world->dropItem($this->position->add(0.5, 0.5, 0.5), $drops);
|
||||
}
|
||||
|
||||
$this->setPlant(null);
|
||||
|
@ -73,7 +73,7 @@ class Furnace extends Opaque{
|
||||
$furnace = $world->getTile($this->position);
|
||||
if($furnace instanceof TileFurnace && $furnace->onUpdate()){
|
||||
if(mt_rand(1, 60) === 1){ //in vanilla this is between 1 and 5 seconds; try to average about 3
|
||||
$world->addSound($this->position->center(), $furnace->getFurnaceType()->getCookSound());
|
||||
$world->addSound($this->position, $furnace->getFurnaceType()->getCookSound());
|
||||
}
|
||||
$world->scheduleDelayedBlockUpdate($this->position, 1); //TODO: check this
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\World;
|
||||
use function count;
|
||||
use function shuffle;
|
||||
|
||||
@ -83,8 +84,7 @@ class GlowLichen extends Transparent{
|
||||
return $result->setFace($spreadFace, true);
|
||||
}
|
||||
|
||||
private function spread(BlockPosition $replacePos, int $spreadFace) : bool{
|
||||
$world = $replacePos->getWorld();
|
||||
private function spread(World $world, Vector3 $replacePos, int $spreadFace) : bool{
|
||||
$supportBlock = $world->getBlock($replacePos->getSide($spreadFace));
|
||||
$supportFace = Facing::opposite($spreadFace);
|
||||
|
||||
@ -117,10 +117,12 @@ class GlowLichen extends Transparent{
|
||||
}
|
||||
|
||||
private function spreadAroundSupport(int $sourceFace) : bool{
|
||||
$world = $this->position->getWorld();
|
||||
|
||||
$supportPos = $this->position->getSide($sourceFace);
|
||||
foreach(self::getShuffledSpreadFaces($sourceFace) as $spreadFace){
|
||||
$replacePos = $supportPos->getSide($spreadFace);
|
||||
if($this->spread($replacePos, Facing::opposite($spreadFace))){
|
||||
if($this->spread($world, $replacePos, Facing::opposite($spreadFace))){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -129,9 +131,11 @@ class GlowLichen extends Transparent{
|
||||
}
|
||||
|
||||
private function spreadAdjacentToSupport(int $sourceFace) : bool{
|
||||
$world = $this->position->getWorld();
|
||||
|
||||
foreach(self::getShuffledSpreadFaces($sourceFace) as $spreadFace){
|
||||
$replacePos = $this->position->getSide($spreadFace);
|
||||
if($this->spread($replacePos, $sourceFace)){
|
||||
if($this->spread($world, $replacePos, $sourceFace)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -140,7 +144,7 @@ class GlowLichen extends Transparent{
|
||||
|
||||
private function spreadWithinSelf(int $sourceFace) : bool{
|
||||
foreach(self::getShuffledSpreadFaces($sourceFace) as $spreadFace){
|
||||
if(!$this->hasFace($spreadFace) && $this->spread($this->position, $spreadFace)){
|
||||
if(!$this->hasFace($spreadFace) && $this->spread($this->position->getWorld(), $this->position, $spreadFace)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ class Grass extends Opaque{
|
||||
$world = $this->position->getWorld();
|
||||
if($item instanceof Fertilizer){
|
||||
$item->pop();
|
||||
TallGrassObject::growGrass($world, $this->position->center(), new Random(mt_rand()), 8, 2);
|
||||
TallGrassObject::growGrass($world, $this->position, new Random(mt_rand()), 8, 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -96,14 +96,14 @@ class Grass extends Opaque{
|
||||
if($item instanceof Hoe){
|
||||
$item->applyDamage(1);
|
||||
$newBlock = VanillaBlocks::FARMLAND();
|
||||
$world->addSound($this->position->center(), new ItemUseOnBlockSound($newBlock));
|
||||
$world->addSound($this->position->add(0.5, 0.5, 0.5), new ItemUseOnBlockSound($newBlock));
|
||||
$world->setBlock($this->position, $newBlock);
|
||||
|
||||
return true;
|
||||
}elseif($item instanceof Shovel){
|
||||
$item->applyDamage(1);
|
||||
$newBlock = VanillaBlocks::GRASS_PATH();
|
||||
$world->addSound($this->position->center(), new ItemUseOnBlockSound($newBlock));
|
||||
$world->addSound($this->position->add(0.5, 0.5, 0.5), new ItemUseOnBlockSound($newBlock));
|
||||
$world->setBlock($this->position, $newBlock);
|
||||
|
||||
return true;
|
||||
|
@ -26,6 +26,7 @@ namespace pocketmine\block;
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\item\enchantment\VanillaEnchantments;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\permission\DefaultPermissionNames;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
class Ice extends Transparent{
|
||||
@ -39,7 +40,8 @@ class Ice extends Transparent{
|
||||
}
|
||||
|
||||
public function onBreak(Item $item, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if(($player === null || $player->isSurvival()) && !$item->hasEnchantment(VanillaEnchantments::SILK_TOUCH())){
|
||||
//TODO: we should probably pass instaBreak in here, since events can override it
|
||||
if(($player === null || !$player->hasPermission(DefaultPermissionNames::GAME_BLOCK_DELETE)) && !$item->hasEnchantment(VanillaEnchantments::SILK_TOUCH())){
|
||||
$this->position->getWorld()->setBlock($this->position, VanillaBlocks::WATER());
|
||||
return true;
|
||||
}
|
||||
|
@ -135,11 +135,11 @@ class ItemFrame extends Flowable{
|
||||
if($this->framedItem !== null){
|
||||
$this->itemRotation = ($this->itemRotation + 1) % self::ROTATIONS;
|
||||
|
||||
$this->position->getWorld()->addSound($this->position->center(), new ItemFrameRotateItemSound());
|
||||
$this->position->getWorld()->addSound($this->position, new ItemFrameRotateItemSound());
|
||||
}elseif(!$item->isNull()){
|
||||
$this->framedItem = $item->pop();
|
||||
|
||||
$this->position->getWorld()->addSound($this->position->center(), new ItemFrameAddItemSound());
|
||||
$this->position->getWorld()->addSound($this->position, new ItemFrameAddItemSound());
|
||||
}else{
|
||||
return true;
|
||||
}
|
||||
@ -155,8 +155,8 @@ class ItemFrame extends Flowable{
|
||||
}
|
||||
$world = $this->position->getWorld();
|
||||
if(Utils::getRandomFloat() <= $this->itemDropChance){
|
||||
$world->dropItem($this->position->center(), clone $this->framedItem);
|
||||
$world->addSound($this->position->center(), new ItemFrameRemoveItemSound());
|
||||
$world->dropItem($this->position->add(0.5, 0.5, 0.5), clone $this->framedItem);
|
||||
$world->addSound($this->position, new ItemFrameRemoveItemSound());
|
||||
}
|
||||
$this->setFramedItem(null);
|
||||
$world->setBlock($this->position, $this);
|
||||
|
@ -61,7 +61,7 @@ class Jukebox extends Opaque{
|
||||
|
||||
public function ejectRecord() : void{
|
||||
if($this->record !== null){
|
||||
$this->position->getWorld()->dropItem($this->position->asVector3()->add(0.5, 1, 0.5), $this->record);
|
||||
$this->position->getWorld()->dropItem($this->position->add(0.5, 1, 0.5), $this->record);
|
||||
$this->record = null;
|
||||
$this->stopSound();
|
||||
}
|
||||
@ -76,12 +76,12 @@ class Jukebox extends Opaque{
|
||||
|
||||
public function startSound() : void{
|
||||
if($this->record !== null){
|
||||
$this->position->getWorld()->addSound($this->position->center(), new RecordSound($this->record->getRecordType()));
|
||||
$this->position->getWorld()->addSound($this->position, new RecordSound($this->record->getRecordType()));
|
||||
}
|
||||
}
|
||||
|
||||
public function stopSound() : void{
|
||||
$this->position->getWorld()->addSound($this->position->center(), new RecordStopSound());
|
||||
$this->position->getWorld()->addSound($this->position, new RecordStopSound());
|
||||
}
|
||||
|
||||
public function onBreak(Item $item, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
|
@ -51,7 +51,7 @@ class Ladder extends Transparent{
|
||||
}
|
||||
|
||||
public function onEntityInside(Entity $entity) : bool{
|
||||
if($entity instanceof Living && $entity->getPosition()->floor()->distanceSquared($this->position->asVector3()) < 1){ //entity coordinates must be inside block
|
||||
if($entity instanceof Living && $entity->getPosition()->floor()->distanceSquared($this->position) < 1){ //entity coordinates must be inside block
|
||||
$entity->resetFallDistance();
|
||||
$entity->onGround = true;
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ class Leaves extends Transparent{
|
||||
* @phpstan-param array<int, true> $visited
|
||||
* @phpstan-param-out array<int, true> $visited
|
||||
*/
|
||||
protected function findLog(BlockPosition $pos, array &$visited = [], int $distance = 0) : bool{
|
||||
protected function findLog(Vector3 $pos, array &$visited = [], int $distance = 0) : bool{
|
||||
$index = World::blockHash($pos->x, $pos->y, $pos->z);
|
||||
if(isset($visited[$index])){
|
||||
return false;
|
||||
|
@ -123,7 +123,7 @@ class Lectern extends Transparent{
|
||||
if($this->book === null && $item instanceof WritableBookBase){
|
||||
$world = $this->position->getWorld();
|
||||
$world->setBlock($this->position, $this->setBook($item));
|
||||
$world->addSound($this->position->center(), new LecternPlaceBookSound());
|
||||
$world->addSound($this->position, new LecternPlaceBookSound());
|
||||
$item->pop();
|
||||
}
|
||||
return true;
|
||||
@ -132,7 +132,7 @@ class Lectern extends Transparent{
|
||||
public function onAttack(Item $item, int $face, ?Player $player = null) : bool{
|
||||
if($this->book !== null){
|
||||
$world = $this->position->getWorld();
|
||||
$world->dropItem($this->position->getSide(Facing::UP)->center(), $this->book);
|
||||
$world->dropItem($this->position->up(), $this->book);
|
||||
$world->setBlock($this->position, $this->setBook(null));
|
||||
}
|
||||
return false;
|
||||
|
@ -95,7 +95,7 @@ class Lever extends Flowable{
|
||||
$world = $this->position->getWorld();
|
||||
$world->setBlock($this->position, $this);
|
||||
$world->addSound(
|
||||
$this->position->center(),
|
||||
$this->position->add(0.5, 0.5, 0.5),
|
||||
$this->activated ? new RedstonePowerOnSound() : new RedstonePowerOffSound()
|
||||
);
|
||||
return true;
|
||||
|
@ -165,9 +165,9 @@ abstract class Liquid extends Transparent{
|
||||
|
||||
$vX = $vY = $vZ = 0;
|
||||
|
||||
$x = $this->position->x;
|
||||
$y = $this->position->y;
|
||||
$z = $this->position->z;
|
||||
$x = $this->position->getFloorX();
|
||||
$y = $this->position->getFloorY();
|
||||
$z = $this->position->getFloorZ();
|
||||
|
||||
$decay = $this->getEffectiveFlowDecay($this);
|
||||
|
||||
@ -259,9 +259,9 @@ abstract class Liquid extends Transparent{
|
||||
|
||||
$world = $this->position->getWorld();
|
||||
|
||||
$x = $this->position->x;
|
||||
$y = $this->position->y;
|
||||
$z = $this->position->z;
|
||||
$x = $this->position->getFloorX();
|
||||
$y = $this->position->getFloorY();
|
||||
$z = $this->position->getFloorZ();
|
||||
|
||||
if(!$this->isSource()){
|
||||
$smallestFlowDecay = -100;
|
||||
@ -368,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->center(), 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 + (Utils::getRandomFloat() - Utils::getRandomFloat()) * 0.8));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ class NetherVines extends Flowable{
|
||||
|
||||
for($i = 1; $i <= $growthAmount; $i++){
|
||||
$growthPos = $pos->getSide($this->growthFace, $i);
|
||||
if(!$world->isInWorld($growthPos->x, $growthPos->y, $growthPos->z) || !$world->getBlock($growthPos)->canBeReplaced()){
|
||||
if(!$world->isInWorld($growthPos->getFloorX(), $growthPos->getFloorY(), $growthPos->getFloorZ()) || !$world->getBlock($growthPos)->canBeReplaced()){
|
||||
break;
|
||||
}
|
||||
$tx->addBlock($growthPos, (clone $top)->setAge(min(++$age, self::MAX_AGE)));
|
||||
|
@ -89,7 +89,7 @@ class PinkPetals extends Flowable{
|
||||
if($this->count < self::MAX_COUNT){
|
||||
$grew = BlockEventHelper::grow($this, (clone $this)->setCount($this->count + 1), $player);
|
||||
}else{
|
||||
$this->position->getWorld()->dropItem($this->position->center(), $this->asItem());
|
||||
$this->position->getWorld()->dropItem($this->position->add(0, 0.5, 0), $this->asItem());
|
||||
$grew = true;
|
||||
}
|
||||
if($grew){
|
||||
|
@ -73,7 +73,7 @@ final class PitcherCrop extends Flowable{
|
||||
|
||||
$tx = new BlockTransaction($this->position->getWorld());
|
||||
$tx->addBlock($this->position, VanillaBlocks::DOUBLE_PITCHER_CROP()->setTop(false));
|
||||
$tx->addBlock($this->position->getSide(Facing::UP), VanillaBlocks::DOUBLE_PITCHER_CROP()->setTop(true));
|
||||
$tx->addBlock($this->position->up(), VanillaBlocks::DOUBLE_PITCHER_CROP()->setTop(true));
|
||||
|
||||
$ev = new StructureGrowEvent($this, $tx, $player);
|
||||
$ev->call();
|
||||
|
@ -27,7 +27,6 @@ use pocketmine\block\tile\Cauldron as TileCauldron;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemTypeIds;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\sound\CauldronEmptyPotionSound;
|
||||
@ -108,10 +107,10 @@ final class PotionCauldron extends FillableCauldron{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
$world = $this->position->getWorld();
|
||||
if($this->getSide(Facing::UP)->getTypeId() === BlockTypeIds::WATER){
|
||||
if($world->getBlock($this->position->up())->getTypeId() === BlockTypeIds::WATER){
|
||||
$cauldron = VanillaBlocks::WATER_CAULDRON()->setFillLevel(FillableCauldron::MAX_FILL_LEVEL);
|
||||
$world->setBlock($this->position, $cauldron);
|
||||
$world->addSound($this->position->center(), $cauldron->getFillSound());
|
||||
$world->addSound($this->position->add(0.5, 0.5, 0.5), $cauldron->getFillSound());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ abstract class PressurePlate extends Transparent{
|
||||
if($newState !== null){
|
||||
$world->setBlock($this->position, $newState);
|
||||
if($pressedChange !== null){
|
||||
$world->addSound($this->position->center(), $pressedChange ?
|
||||
$world->addSound($this->position, $pressedChange ?
|
||||
new PressurePlateActivateSound($this) :
|
||||
new PressurePlateDeactivateSound($this)
|
||||
);
|
||||
|
@ -38,7 +38,7 @@ class Pumpkin extends Opaque{
|
||||
$item->applyDamage(1);
|
||||
$world = $this->position->getWorld();
|
||||
$world->setBlock($this->position, VanillaBlocks::CARVED_PUMPKIN()->setFacing($face));
|
||||
$world->dropItem($this->position->center(), VanillaItems::PUMPKIN_SEEDS()->setCount(1));
|
||||
$world->dropItem($this->position->add(0.5, 0.5, 0.5), VanillaItems::PUMPKIN_SEEDS()->setCount(1));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -81,7 +81,7 @@ class Sapling extends Flowable{
|
||||
|
||||
public function onRandomTick() : void{
|
||||
$world = $this->position->getWorld();
|
||||
if($world->getFullLightAt($this->position->x, $this->position->y, $this->position->z) >= 8 && mt_rand(1, 7) === 1){
|
||||
if($world->getFullLightAt($this->position->getFloorX(), $this->position->getFloorY(), $this->position->getFloorZ()) >= 8 && mt_rand(1, 7) === 1){
|
||||
if($this->ready){
|
||||
$this->grow(null);
|
||||
}else{
|
||||
@ -94,7 +94,7 @@ class Sapling extends Flowable{
|
||||
private function grow(?Player $player) : bool{
|
||||
$random = new Random(mt_rand());
|
||||
$tree = TreeFactory::get($random, $this->saplingType->getTreeType());
|
||||
$transaction = $tree?->getBlockTransaction($this->position->getWorld(), $this->position->x, $this->position->y, $this->position->z, $random);
|
||||
$transaction = $tree?->getBlockTransaction($this->position->getWorld(), $this->position->getFloorX(), $this->position->getFloorY(), $this->position->getFloorZ(), $random);
|
||||
if($transaction === null){
|
||||
return false;
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\Position;
|
||||
use function mt_rand;
|
||||
|
||||
class SmallDripleaf extends Transparent{
|
||||
@ -97,9 +98,9 @@ class SmallDripleaf extends Transparent{
|
||||
return false;
|
||||
}
|
||||
|
||||
private function canGrowTo(BlockPosition $pos) : bool{
|
||||
private function canGrowTo(Position $pos) : bool{
|
||||
$world = $pos->getWorld();
|
||||
if(!$world->isInWorld($pos->x, $pos->y, $pos->z)){
|
||||
if(!$world->isInWorld($pos->getFloorX(), $pos->getFloorY(), $pos->getFloorZ())){
|
||||
return false;
|
||||
}
|
||||
$block = $world->getBlock($pos);
|
||||
|
@ -32,6 +32,7 @@ use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
class Sugarcane extends Flowable{
|
||||
use AgeableTrait;
|
||||
@ -41,16 +42,16 @@ class Sugarcane extends Flowable{
|
||||
|
||||
public const MAX_AGE = 15;
|
||||
|
||||
private function seekToBottom() : BlockPosition{
|
||||
private function seekToBottom() : Position{
|
||||
$world = $this->position->getWorld();
|
||||
$bottom = $this->position;
|
||||
while(($next = $world->getBlock($bottom->getSide(Facing::DOWN)))->hasSameTypeId($this)){
|
||||
while(($next = $world->getBlock($bottom->down()))->hasSameTypeId($this)){
|
||||
$bottom = $next->position;
|
||||
}
|
||||
return $bottom;
|
||||
}
|
||||
|
||||
private function grow(BlockPosition $pos, ?Player $player = null) : bool{
|
||||
private function grow(Position $pos, ?Player $player = null) : bool{
|
||||
$grew = false;
|
||||
$world = $pos->getWorld();
|
||||
for($y = 1; $y < 3; ++$y){
|
||||
|
@ -81,9 +81,8 @@ class SweetBerryBush extends Flowable{
|
||||
}
|
||||
}elseif(($dropAmount = $this->getBerryDropAmount()) > 0){
|
||||
$world->setBlock($this->position, $this->setAge(self::STAGE_BUSH_NO_BERRIES));
|
||||
$posV3 = $this->position->center();
|
||||
$world->dropItem($posV3, $this->asItem()->setCount($dropAmount));
|
||||
$world->addSound($posV3, new SweetBerriesPickSound());
|
||||
$world->dropItem($this->position, $this->asItem()->setCount($dropAmount));
|
||||
$world->addSound($this->position, new SweetBerriesPickSound());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -100,7 +100,7 @@ class TNT extends Opaque{
|
||||
|
||||
$mot = (new Random())->nextSignedFloat() * M_PI * 2;
|
||||
|
||||
$tnt = new PrimedTNT(Location::fromObject($this->position->asVector3()->add(0.5, 0, 0.5), $world));
|
||||
$tnt = new PrimedTNT(Location::fromObject($this->position->add(0.5, 0, 0.5), $world));
|
||||
$tnt->setFuse($fuse);
|
||||
$tnt->setWorksUnderwater($this->worksUnderwater);
|
||||
$tnt->setMotion(new Vector3(-sin($mot) * 0.02, 0.2, -cos($mot) * 0.02));
|
||||
|
@ -88,7 +88,7 @@ class Trapdoor extends Transparent{
|
||||
$this->open = !$this->open;
|
||||
$world = $this->position->getWorld();
|
||||
$world->setBlock($this->position, $this);
|
||||
$world->addSound($this->position->center(), new DoorSound());
|
||||
$world->addSound($this->position, new DoorSound());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,6 @@ use pocketmine\block\tile\MonsterSpawner as TileMonsterSpawner;
|
||||
use pocketmine\block\tile\NormalFurnace as TileNormalFurnace;
|
||||
use pocketmine\block\tile\Note as TileNote;
|
||||
use pocketmine\block\tile\ShulkerBox as TileShulkerBox;
|
||||
use pocketmine\block\tile\Sign as TileSign;
|
||||
use pocketmine\block\tile\Smoker as TileSmoker;
|
||||
use pocketmine\block\tile\Tile;
|
||||
use pocketmine\block\utils\AmethystTrait;
|
||||
@ -783,8 +782,8 @@ use function strtolower;
|
||||
* @method static Water WATER()
|
||||
* @method static WaterCauldron WATER_CAULDRON()
|
||||
* @method static NetherVines WEEPING_VINES()
|
||||
* @method static WeightedPressurePlate WEIGHTED_PRESSURE_PLATE_HEAVY()
|
||||
* @method static WeightedPressurePlate WEIGHTED_PRESSURE_PLATE_LIGHT()
|
||||
* @method static WeightedPressurePlateHeavy WEIGHTED_PRESSURE_PLATE_HEAVY()
|
||||
* @method static WeightedPressurePlateLight WEIGHTED_PRESSURE_PLATE_LIGHT()
|
||||
* @method static Wheat WHEAT()
|
||||
* @method static Flower WHITE_TULIP()
|
||||
* @method static WitherRose WITHER_ROSE()
|
||||
@ -1180,14 +1179,14 @@ final class VanillaBlocks{
|
||||
self::register("lily_pad", fn(BID $id) => new WaterLily($id, "Lily Pad", new Info(BreakInfo::instant())));
|
||||
|
||||
$weightedPressurePlateBreakInfo = new Info(BreakInfo::pickaxe(0.5, ToolTier::WOOD));
|
||||
self::register("weighted_pressure_plate_heavy", fn(BID $id) => new WeightedPressurePlate(
|
||||
self::register("weighted_pressure_plate_heavy", fn(BID $id) => new WeightedPressurePlateHeavy(
|
||||
$id,
|
||||
"Weighted Pressure Plate Heavy",
|
||||
$weightedPressurePlateBreakInfo,
|
||||
deactivationDelayTicks: 10,
|
||||
signalStrengthFactor: 0.1
|
||||
));
|
||||
self::register("weighted_pressure_plate_light", fn(BID $id) => new WeightedPressurePlate(
|
||||
self::register("weighted_pressure_plate_light", fn(BID $id) => new WeightedPressurePlateLight(
|
||||
$id,
|
||||
"Weighted Pressure Plate Light",
|
||||
$weightedPressurePlateBreakInfo,
|
||||
@ -1360,8 +1359,8 @@ final class VanillaBlocks{
|
||||
WoodType::WARPED => VanillaItems::WARPED_SIGN(...),
|
||||
WoodType::CHERRY => VanillaItems::CHERRY_SIGN(...),
|
||||
};
|
||||
self::register($idName("sign"), fn(BID $id) => new FloorSign($id, $name . " Sign", $signBreakInfo, $woodType, $signAsItem), TileSign::class);
|
||||
self::register($idName("wall_sign"), fn(BID $id) => new WallSign($id, $name . " Wall Sign", $signBreakInfo, $woodType, $signAsItem), TileSign::class);
|
||||
self::register($idName("sign"), fn(BID $id) => new FloorSign($id, $name . " Sign", $signBreakInfo, $woodType, $signAsItem));
|
||||
self::register($idName("wall_sign"), fn(BID $id) => new WallSign($id, $name . " Wall Sign", $signBreakInfo, $woodType, $signAsItem));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,6 @@ use pocketmine\item\Potion;
|
||||
use pocketmine\item\PotionType;
|
||||
use pocketmine\item\SplashPotion;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\sound\CauldronAddDyeSound;
|
||||
@ -120,7 +119,7 @@ final class WaterCauldron extends FillableCauldron{
|
||||
}) !== null && ($newColor = $dyeColor->getRgbValue())->toRGBA() !== $this->customWaterColor?->toRGBA()
|
||||
){
|
||||
$world->setBlock($this->position, $this->setCustomWaterColor($this->customWaterColor === null ? $newColor : Color::mix($this->customWaterColor, $newColor)));
|
||||
$world->addSound($this->position->center(), new CauldronAddDyeSound());
|
||||
$world->addSound($this->position->add(0.5, 0.5, 0.5), new CauldronAddDyeSound());
|
||||
|
||||
$item->pop();
|
||||
}elseif($item instanceof Potion || $item instanceof SplashPotion){ //TODO: lingering potion
|
||||
@ -140,12 +139,12 @@ final class WaterCauldron extends FillableCauldron{
|
||||
} && $item->getCustomColor()?->toRGBA() !== $this->customWaterColor->toRGBA()){
|
||||
$item->setCustomColor($this->customWaterColor);
|
||||
$world->setBlock($this->position, $this->withFillLevel($this->getFillLevel() - self::DYE_ARMOR_USE_AMOUNT));
|
||||
$world->addSound($this->position->center(), new CauldronDyeItemSound());
|
||||
$world->addSound($this->position->add(0.5, 0.5, 0.5), new CauldronDyeItemSound());
|
||||
}
|
||||
}elseif($item->getCustomColor() !== null){
|
||||
$item->clearCustomColor();
|
||||
$world->setBlock($this->position, $this->withFillLevel($this->getFillLevel() - self::CLEAN_ARMOR_USE_AMOUNT));
|
||||
$world->addSound($this->position->center(), new CauldronCleanItemSound());
|
||||
$world->addSound($this->position->add(0.5, 0.5, 0.5), new CauldronCleanItemSound());
|
||||
}
|
||||
}elseif($item instanceof Banner){
|
||||
$patterns = $item->getPatterns();
|
||||
@ -154,7 +153,7 @@ final class WaterCauldron extends FillableCauldron{
|
||||
$item->setPatterns($patterns);
|
||||
|
||||
$world->setBlock($this->position, $this->withFillLevel($this->getFillLevel() - self::CLEAN_BANNER_USE_AMOUNT));
|
||||
$world->addSound($this->position->center(), new CauldronCleanItemSound());
|
||||
$world->addSound($this->position->add(0.5, 0.5, 0.5), new CauldronCleanItemSound());
|
||||
}
|
||||
}elseif(ItemTypeIds::toBlockTypeId($item->getTypeId()) === BlockTypeIds::DYED_SHULKER_BOX){
|
||||
if($this->customWaterColor === null){
|
||||
@ -165,7 +164,7 @@ final class WaterCauldron extends FillableCauldron{
|
||||
$returnedItems[] = $newItem;
|
||||
|
||||
$world->setBlock($this->position, $this->withFillLevel($this->getFillLevel() - self::CLEAN_SHULKER_BOX_USE_AMOUNT));
|
||||
$world->addSound($this->position->center(), new CauldronCleanItemSound());
|
||||
$world->addSound($this->position->add(0.5, 0.5, 0.5), new CauldronCleanItemSound());
|
||||
}
|
||||
}else{
|
||||
match($item->getTypeId()){
|
||||
@ -196,13 +195,13 @@ final class WaterCauldron extends FillableCauldron{
|
||||
public function onNearbyBlockChange() : void{
|
||||
$hasCustomWaterColor = $this->customWaterColor !== null;
|
||||
if($this->getFillLevel() < self::MAX_FILL_LEVEL || $hasCustomWaterColor){
|
||||
if($this->getSide(Facing::UP)->getTypeId() === BlockTypeIds::WATER){
|
||||
$world = $this->position->getWorld();
|
||||
if($world->getBlock($this->position->up())->getTypeId() === BlockTypeIds::WATER){
|
||||
if($hasCustomWaterColor){
|
||||
//TODO: particles
|
||||
}
|
||||
$world = $this->position->getWorld();
|
||||
$world->setBlock($this->position, $this->setCustomWaterColor(null)->setFillLevel(FillableCauldron::MAX_FILL_LEVEL));
|
||||
$world->addSound($this->position->center(), $this->getFillSound());
|
||||
$world->addSound($this->position->add(0.5, 0.5, 0.5), $this->getFillSound());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
31
src/block/WeightedPressurePlateHeavy.php
Normal file
31
src/block/WeightedPressurePlateHeavy.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
class WeightedPressurePlateHeavy extends WeightedPressurePlate{
|
||||
|
||||
}
|
31
src/block/WeightedPressurePlateLight.php
Normal file
31
src/block/WeightedPressurePlateLight.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
class WeightedPressurePlateLight extends WeightedPressurePlate{
|
||||
|
||||
}
|
@ -67,7 +67,7 @@ class Wood extends Opaque{
|
||||
$item->applyDamage(1);
|
||||
$this->stripped = true;
|
||||
$this->position->getWorld()->setBlock($this->position, $this);
|
||||
$this->position->getWorld()->addSound($this->position->center(), new ItemUseOnBlockSound($this));
|
||||
$this->position->getWorld()->addSound($this->position, new ItemUseOnBlockSound($this));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -50,7 +50,7 @@ trait AnimatedBlockInventoryTrait{
|
||||
if($this->holder->isValid() && $this->getViewerCount() === 1){
|
||||
//TODO: this crap really shouldn't be managed by the inventory
|
||||
$this->animateBlock(true);
|
||||
$this->holder->getWorld()->addSound($this->holder->center(), $this->getOpenSound());
|
||||
$this->holder->getWorld()->addSound($this->holder->add(0.5, 0.5, 0.5), $this->getOpenSound());
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ trait AnimatedBlockInventoryTrait{
|
||||
if($this->holder->isValid() && $this->getViewerCount() === 1){
|
||||
//TODO: this crap really shouldn't be managed by the inventory
|
||||
$this->animateBlock(false);
|
||||
$this->holder->getWorld()->addSound($this->holder->center(), $this->getCloseSound());
|
||||
$this->holder->getWorld()->addSound($this->holder->add(0.5, 0.5, 0.5), $this->getCloseSound());
|
||||
}
|
||||
parent::onClose($who);
|
||||
}
|
||||
|
@ -23,9 +23,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\inventory;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\inventory\SimpleInventory;
|
||||
use pocketmine\inventory\TemporaryInventory;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
class AnvilInventory extends SimpleInventory implements BlockInventory, TemporaryInventory{
|
||||
use BlockInventoryTrait;
|
||||
@ -33,7 +33,7 @@ class AnvilInventory extends SimpleInventory implements BlockInventory, Temporar
|
||||
public const SLOT_INPUT = 0;
|
||||
public const SLOT_MATERIAL = 1;
|
||||
|
||||
public function __construct(BlockPosition $holder){
|
||||
public function __construct(Position $holder){
|
||||
$this->holder = $holder;
|
||||
parent::__construct(2);
|
||||
}
|
||||
|
@ -24,8 +24,8 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block\inventory;
|
||||
|
||||
use pocketmine\block\Barrel;
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\inventory\SimpleInventory;
|
||||
use pocketmine\world\Position;
|
||||
use pocketmine\world\sound\BarrelCloseSound;
|
||||
use pocketmine\world\sound\BarrelOpenSound;
|
||||
use pocketmine\world\sound\Sound;
|
||||
@ -33,7 +33,7 @@ use pocketmine\world\sound\Sound;
|
||||
class BarrelInventory extends SimpleInventory implements BlockInventory{
|
||||
use AnimatedBlockInventoryTrait;
|
||||
|
||||
public function __construct(BlockPosition $holder){
|
||||
public function __construct(Position $holder){
|
||||
$this->holder = $holder;
|
||||
parent::__construct(27);
|
||||
}
|
||||
|
@ -23,8 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\inventory;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
interface BlockInventory{
|
||||
public function getHolder() : BlockPosition;
|
||||
public function getHolder() : Position;
|
||||
}
|
||||
|
@ -23,12 +23,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\inventory;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
trait BlockInventoryTrait{
|
||||
protected BlockPosition $holder;
|
||||
protected Position $holder;
|
||||
|
||||
public function getHolder() : BlockPosition{
|
||||
public function getHolder() : Position{
|
||||
return $this->holder;
|
||||
}
|
||||
}
|
||||
|
@ -23,8 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\inventory;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\inventory\SimpleInventory;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
class BrewingStandInventory extends SimpleInventory implements BlockInventory{
|
||||
use BlockInventoryTrait;
|
||||
@ -35,7 +35,7 @@ class BrewingStandInventory extends SimpleInventory implements BlockInventory{
|
||||
public const SLOT_BOTTLE_RIGHT = 3;
|
||||
public const SLOT_FUEL = 4;
|
||||
|
||||
public function __construct(BlockPosition $holder, int $size = 5){
|
||||
public function __construct(Position $holder, int $size = 5){
|
||||
$this->holder = $holder;
|
||||
parent::__construct($size);
|
||||
}
|
||||
|
@ -23,13 +23,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\inventory;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\inventory\SimpleInventory;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
class CampfireInventory extends SimpleInventory implements BlockInventory{
|
||||
use BlockInventoryTrait;
|
||||
|
||||
public function __construct(BlockPosition $holder){
|
||||
public function __construct(Position $holder){
|
||||
$this->holder = $holder;
|
||||
parent::__construct(4);
|
||||
}
|
||||
|
@ -23,14 +23,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\inventory;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\inventory\SimpleInventory;
|
||||
use pocketmine\inventory\TemporaryInventory;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
final class CartographyTableInventory extends SimpleInventory implements BlockInventory, TemporaryInventory{
|
||||
use BlockInventoryTrait;
|
||||
|
||||
public function __construct(BlockPosition $holder){
|
||||
public function __construct(Position $holder){
|
||||
$this->holder = $holder;
|
||||
parent::__construct(2);
|
||||
}
|
||||
|
@ -23,10 +23,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\inventory;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\inventory\SimpleInventory;
|
||||
use pocketmine\network\mcpe\protocol\BlockEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\BlockPosition as ProtocolBlockPosition;
|
||||
use pocketmine\network\mcpe\protocol\types\BlockPosition;
|
||||
use pocketmine\world\Position;
|
||||
use pocketmine\world\sound\ChestCloseSound;
|
||||
use pocketmine\world\sound\ChestOpenSound;
|
||||
use pocketmine\world\sound\Sound;
|
||||
@ -34,7 +34,7 @@ use pocketmine\world\sound\Sound;
|
||||
class ChestInventory extends SimpleInventory implements BlockInventory{
|
||||
use AnimatedBlockInventoryTrait;
|
||||
|
||||
public function __construct(BlockPosition $holder){
|
||||
public function __construct(Position $holder){
|
||||
$this->holder = $holder;
|
||||
parent::__construct(27);
|
||||
}
|
||||
@ -51,6 +51,6 @@ class ChestInventory extends SimpleInventory implements BlockInventory{
|
||||
$holder = $this->getHolder();
|
||||
|
||||
//event ID is always 1 for a chest
|
||||
$holder->getWorld()->broadcastPacketOnBlock($holder, BlockEventPacket::create(new ProtocolBlockPosition($holder->x, $holder->y, $holder->z), 1, $isOpen ? 1 : 0));
|
||||
$holder->getWorld()->broadcastPacketToViewers($holder, BlockEventPacket::create(BlockPosition::fromVector3($holder), 1, $isOpen ? 1 : 0));
|
||||
}
|
||||
}
|
||||
|
@ -23,14 +23,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\inventory;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\crafting\CraftingGrid;
|
||||
use pocketmine\inventory\TemporaryInventory;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
final class CraftingTableInventory extends CraftingGrid implements BlockInventory, TemporaryInventory{
|
||||
use BlockInventoryTrait;
|
||||
|
||||
public function __construct(BlockPosition $holder){
|
||||
public function __construct(Position $holder){
|
||||
$this->holder = $holder;
|
||||
parent::__construct(CraftingGrid::SIZE_BIG);
|
||||
}
|
||||
|
@ -23,13 +23,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\inventory;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\event\player\PlayerEnchantingOptionsRequestEvent;
|
||||
use pocketmine\inventory\SimpleInventory;
|
||||
use pocketmine\inventory\TemporaryInventory;
|
||||
use pocketmine\item\enchantment\EnchantingHelper as Helper;
|
||||
use pocketmine\item\enchantment\EnchantingOption;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\world\Position;
|
||||
use function array_values;
|
||||
use function count;
|
||||
|
||||
@ -45,7 +45,7 @@ class EnchantInventory extends SimpleInventory implements BlockInventory, Tempor
|
||||
*/
|
||||
private array $options = [];
|
||||
|
||||
public function __construct(BlockPosition $holder){
|
||||
public function __construct(Position $holder){
|
||||
$this->holder = $holder;
|
||||
parent::__construct(2);
|
||||
}
|
||||
|
@ -23,14 +23,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\inventory;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\block\tile\EnderChest;
|
||||
use pocketmine\inventory\DelegateInventory;
|
||||
use pocketmine\inventory\Inventory;
|
||||
use pocketmine\inventory\PlayerEnderInventory;
|
||||
use pocketmine\network\mcpe\protocol\BlockEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\BlockPosition as ProtocolBlockPosition;
|
||||
use pocketmine\network\mcpe\protocol\types\BlockPosition;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\Position;
|
||||
use pocketmine\world\sound\EnderChestCloseSound;
|
||||
use pocketmine\world\sound\EnderChestOpenSound;
|
||||
use pocketmine\world\sound\Sound;
|
||||
@ -44,7 +44,7 @@ class EnderChestInventory extends DelegateInventory implements BlockInventory{
|
||||
}
|
||||
|
||||
public function __construct(
|
||||
BlockPosition $holder,
|
||||
Position $holder,
|
||||
private PlayerEnderInventory $inventory
|
||||
){
|
||||
parent::__construct($inventory);
|
||||
@ -75,7 +75,7 @@ class EnderChestInventory extends DelegateInventory implements BlockInventory{
|
||||
$holder = $this->getHolder();
|
||||
|
||||
//event ID is always 1 for a chest
|
||||
$holder->getWorld()->broadcastPacketOnBlock($holder, BlockEventPacket::create(new ProtocolBlockPosition($holder->x, $holder->y, $holder->z), 1, $isOpen ? 1 : 0));
|
||||
$holder->getWorld()->broadcastPacketToViewers($holder, BlockEventPacket::create(BlockPosition::fromVector3($holder), 1, $isOpen ? 1 : 0));
|
||||
}
|
||||
|
||||
public function onClose(Player $who) : void{
|
||||
|
@ -23,10 +23,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\inventory;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\crafting\FurnaceType;
|
||||
use pocketmine\inventory\SimpleInventory;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
class FurnaceInventory extends SimpleInventory implements BlockInventory{
|
||||
use BlockInventoryTrait;
|
||||
@ -36,7 +36,7 @@ class FurnaceInventory extends SimpleInventory implements BlockInventory{
|
||||
public const SLOT_RESULT = 2;
|
||||
|
||||
public function __construct(
|
||||
BlockPosition $holder,
|
||||
Position $holder,
|
||||
private FurnaceType $furnaceType
|
||||
){
|
||||
$this->holder = $holder;
|
||||
|
@ -23,13 +23,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\inventory;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\inventory\SimpleInventory;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
class HopperInventory extends SimpleInventory implements BlockInventory{
|
||||
use BlockInventoryTrait;
|
||||
|
||||
public function __construct(BlockPosition $holder, int $size = 5){
|
||||
public function __construct(Position $holder, int $size = 5){
|
||||
$this->holder = $holder;
|
||||
parent::__construct($size);
|
||||
}
|
||||
|
@ -23,9 +23,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\inventory;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\inventory\SimpleInventory;
|
||||
use pocketmine\inventory\TemporaryInventory;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
final class LoomInventory extends SimpleInventory implements BlockInventory, TemporaryInventory{
|
||||
use BlockInventoryTrait;
|
||||
@ -34,7 +34,7 @@ final class LoomInventory extends SimpleInventory implements BlockInventory, Tem
|
||||
public const SLOT_DYE = 1;
|
||||
public const SLOT_PATTERN = 2;
|
||||
|
||||
public function __construct(BlockPosition $holder, int $size = 3){
|
||||
public function __construct(Position $holder, int $size = 3){
|
||||
$this->holder = $holder;
|
||||
parent::__construct($size);
|
||||
}
|
||||
|
@ -23,13 +23,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\inventory;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\block\BlockTypeIds;
|
||||
use pocketmine\inventory\SimpleInventory;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemTypeIds;
|
||||
use pocketmine\network\mcpe\protocol\BlockEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\BlockPosition as ProtocolBlockPosition;
|
||||
use pocketmine\network\mcpe\protocol\types\BlockPosition;
|
||||
use pocketmine\world\Position;
|
||||
use pocketmine\world\sound\ShulkerBoxCloseSound;
|
||||
use pocketmine\world\sound\ShulkerBoxOpenSound;
|
||||
use pocketmine\world\sound\Sound;
|
||||
@ -37,7 +37,7 @@ use pocketmine\world\sound\Sound;
|
||||
class ShulkerBoxInventory extends SimpleInventory implements BlockInventory{
|
||||
use AnimatedBlockInventoryTrait;
|
||||
|
||||
public function __construct(BlockPosition $holder){
|
||||
public function __construct(Position $holder){
|
||||
$this->holder = $holder;
|
||||
parent::__construct(27);
|
||||
}
|
||||
@ -62,6 +62,6 @@ class ShulkerBoxInventory extends SimpleInventory implements BlockInventory{
|
||||
$holder = $this->getHolder();
|
||||
|
||||
//event ID is always 1 for a chest
|
||||
$holder->getWorld()->broadcastPacketOnBlock($holder, BlockEventPacket::create(new ProtocolBlockPosition($holder->x, $holder->y, $holder->z), 1, $isOpen ? 1 : 0));
|
||||
$holder->getWorld()->broadcastPacketToViewers($holder, BlockEventPacket::create(BlockPosition::fromVector3($holder), 1, $isOpen ? 1 : 0));
|
||||
}
|
||||
}
|
||||
|
@ -23,14 +23,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\inventory;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\inventory\SimpleInventory;
|
||||
use pocketmine\inventory\TemporaryInventory;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
final class SmithingTableInventory extends SimpleInventory implements BlockInventory, TemporaryInventory{
|
||||
use BlockInventoryTrait;
|
||||
|
||||
public function __construct(BlockPosition $holder){
|
||||
public function __construct(Position $holder){
|
||||
$this->holder = $holder;
|
||||
parent::__construct(3);
|
||||
}
|
||||
|
@ -23,16 +23,16 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\inventory;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\inventory\SimpleInventory;
|
||||
use pocketmine\inventory\TemporaryInventory;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
class StonecutterInventory extends SimpleInventory implements BlockInventory, TemporaryInventory{
|
||||
use BlockInventoryTrait;
|
||||
|
||||
public const SLOT_INPUT = 0;
|
||||
|
||||
public function __construct(BlockPosition $holder){
|
||||
public function __construct(Position $holder){
|
||||
$this->holder = $holder;
|
||||
parent::__construct(1);
|
||||
}
|
||||
|
@ -23,9 +23,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\tile;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\block\inventory\BarrelInventory;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\world\World;
|
||||
|
||||
class Barrel extends Spawnable implements Container, Nameable{
|
||||
use NameableTrait;
|
||||
@ -33,8 +34,8 @@ class Barrel extends Spawnable implements Container, Nameable{
|
||||
|
||||
protected BarrelInventory $inventory;
|
||||
|
||||
public function __construct(BlockPosition $position){
|
||||
parent::__construct($position);
|
||||
public function __construct(World $world, Vector3 $pos){
|
||||
parent::__construct($world, $pos);
|
||||
$this->inventory = new BarrelInventory($this->position);
|
||||
}
|
||||
|
||||
|
@ -88,6 +88,6 @@ final class Bell extends Spawnable{
|
||||
default => throw new AssumptionFailedError("Unreachable")
|
||||
});
|
||||
$nbt->setInt(self::TAG_TICKS, 0);
|
||||
return BlockActorDataPacket::create(new BlockPosition($this->position->x, $this->position->y, $this->position->z), new CacheableNbt($nbt));
|
||||
return BlockActorDataPacket::create(BlockPosition::fromVector3($this->position), new CacheableNbt($nbt));
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\tile;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\block\inventory\BrewingStandInventory;
|
||||
use pocketmine\crafting\BrewingRecipe;
|
||||
use pocketmine\event\block\BrewingFuelUseEvent;
|
||||
@ -32,10 +31,12 @@ use pocketmine\inventory\CallbackInventoryListener;
|
||||
use pocketmine\inventory\Inventory;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\network\mcpe\protocol\ContainerSetDataPacket;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\sound\PotionFinishBrewingSound;
|
||||
use pocketmine\world\World;
|
||||
use function array_map;
|
||||
use function count;
|
||||
|
||||
@ -59,11 +60,11 @@ class BrewingStand extends Spawnable implements Container, Nameable{
|
||||
private int $maxFuelTime = 0;
|
||||
private int $remainingFuelTime = 0;
|
||||
|
||||
public function __construct(BlockPosition $position){
|
||||
parent::__construct($position);
|
||||
public function __construct(World $world, Vector3 $pos){
|
||||
parent::__construct($world, $pos);
|
||||
$this->inventory = new BrewingStandInventory($this->position);
|
||||
$this->inventory->getListeners()->add(CallbackInventoryListener::onAnyChange(static function(Inventory $unused) use ($position) : void{
|
||||
$position->getWorld()->scheduleDelayedBlockUpdate($position, 1);
|
||||
$this->inventory->getListeners()->add(CallbackInventoryListener::onAnyChange(static function(Inventory $unused) use ($world, $pos) : void{
|
||||
$world->scheduleDelayedBlockUpdate($pos, 1);
|
||||
}));
|
||||
}
|
||||
|
||||
@ -214,7 +215,7 @@ class BrewingStand extends Spawnable implements Container, Nameable{
|
||||
}
|
||||
|
||||
if($anythingBrewed){
|
||||
$this->position->getWorld()->addSound($this->position->center(), new PotionFinishBrewingSound());
|
||||
$this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), new PotionFinishBrewingSound());
|
||||
}
|
||||
|
||||
$ingredient->pop();
|
||||
|
@ -23,15 +23,16 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\tile;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\block\Campfire as BlockCampfire;
|
||||
use pocketmine\block\inventory\CampfireInventory;
|
||||
use pocketmine\inventory\CallbackInventoryListener;
|
||||
use pocketmine\inventory\Inventory;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||
use pocketmine\world\World;
|
||||
|
||||
class Campfire extends Spawnable implements Container{
|
||||
use ContainerTrait;
|
||||
@ -50,15 +51,14 @@ class Campfire extends Spawnable implements Container{
|
||||
/** @var array<int, int> */
|
||||
private array $cookingTimes = [];
|
||||
|
||||
public function __construct(BlockPosition $position){
|
||||
parent::__construct($position);
|
||||
public function __construct(World $world, Vector3 $pos){
|
||||
parent::__construct($world, $pos);
|
||||
$this->inventory = new CampfireInventory($this->position);
|
||||
$this->inventory->getListeners()->add(CallbackInventoryListener::onAnyChange(
|
||||
static function(Inventory $unused) use ($position) : void{
|
||||
$world = $position->getWorld();
|
||||
$block = $world->getBlock($position);
|
||||
static function(Inventory $unused) use ($world, $pos) : void{
|
||||
$block = $world->getBlock($pos);
|
||||
if($block instanceof BlockCampfire){
|
||||
$world->setBlock($position, $block);
|
||||
$world->setBlock($pos, $block);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
@ -23,13 +23,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\tile;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\block\inventory\ChestInventory;
|
||||
use pocketmine\block\inventory\DoubleChestInventory;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\world\format\Chunk;
|
||||
use pocketmine\world\World;
|
||||
use function abs;
|
||||
|
||||
class Chest extends Spawnable implements Container, Nameable{
|
||||
@ -50,8 +50,8 @@ class Chest extends Spawnable implements Container, Nameable{
|
||||
private ?int $pairX = null;
|
||||
private ?int $pairZ = null;
|
||||
|
||||
public function __construct(BlockPosition $position){
|
||||
parent::__construct($position);
|
||||
public function __construct(World $world, Vector3 $pos){
|
||||
parent::__construct($world, $pos);
|
||||
$this->inventory = new ChestInventory($this->position);
|
||||
}
|
||||
|
||||
|
@ -23,17 +23,18 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\tile;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\block\utils\ChiseledBookshelfSlot;
|
||||
use pocketmine\data\bedrock\item\SavedItemData;
|
||||
use pocketmine\data\bedrock\item\SavedItemStackData;
|
||||
use pocketmine\data\SavedDataLoadingException;
|
||||
use pocketmine\inventory\SimpleInventory;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\NBT;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\ListTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\world\World;
|
||||
use function count;
|
||||
|
||||
class ChiseledBookshelf extends Tile implements Container{
|
||||
@ -45,8 +46,8 @@ class ChiseledBookshelf extends Tile implements Container{
|
||||
|
||||
private ?ChiseledBookshelfSlot $lastInteractedSlot = null;
|
||||
|
||||
public function __construct(BlockPosition $position){
|
||||
parent::__construct($position);
|
||||
public function __construct(World $world, Vector3 $pos){
|
||||
parent::__construct($world, $pos);
|
||||
$this->inventory = new SimpleInventory(count(ChiseledBookshelfSlot::cases()));
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\tile;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\data\bedrock\item\SavedItemStackData;
|
||||
use pocketmine\data\SavedDataLoadingException;
|
||||
use pocketmine\inventory\Inventory;
|
||||
@ -32,6 +31,7 @@ use pocketmine\nbt\NBT;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\ListTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
/**
|
||||
* This trait implements most methods in the {@link Container} interface. It should only be used by Tiles.
|
||||
@ -90,9 +90,9 @@ trait ContainerTrait{
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Tile::getPosition()
|
||||
* @see Position::asPosition()
|
||||
*/
|
||||
abstract protected function getPosition() : BlockPosition;
|
||||
abstract protected function getPosition() : Position;
|
||||
|
||||
/**
|
||||
* @see Tile::onBlockDestroyedHook()
|
||||
@ -102,7 +102,7 @@ trait ContainerTrait{
|
||||
$pos = $this->getPosition();
|
||||
|
||||
$world = $pos->getWorld();
|
||||
$dropPos = $pos->center();
|
||||
$dropPos = $pos->add(0.5, 0.5, 0.5);
|
||||
foreach($inv->getContents() as $k => $item){
|
||||
$world->dropItem($dropPos, $item);
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\tile;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\block\Furnace as BlockFurnace;
|
||||
use pocketmine\block\inventory\FurnaceInventory;
|
||||
use pocketmine\crafting\FurnaceRecipe;
|
||||
@ -33,9 +32,11 @@ use pocketmine\event\inventory\FurnaceSmeltEvent;
|
||||
use pocketmine\inventory\CallbackInventoryListener;
|
||||
use pocketmine\inventory\Inventory;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\network\mcpe\protocol\ContainerSetDataPacket;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\World;
|
||||
use function array_map;
|
||||
use function max;
|
||||
|
||||
@ -52,12 +53,12 @@ abstract class Furnace extends Spawnable implements Container, Nameable{
|
||||
private int $cookTime = 0;
|
||||
private int $maxFuelTime = 0;
|
||||
|
||||
public function __construct(BlockPosition $position){
|
||||
parent::__construct($position);
|
||||
public function __construct(World $world, Vector3 $pos){
|
||||
parent::__construct($world, $pos);
|
||||
$this->inventory = new FurnaceInventory($this->position, $this->getFurnaceType());
|
||||
$this->inventory->getListeners()->add(CallbackInventoryListener::onAnyChange(
|
||||
static function(Inventory $unused) use ($position) : void{
|
||||
$position->getWorld()->scheduleDelayedBlockUpdate($position, 1);
|
||||
static function(Inventory $unused) use ($world, $pos) : void{
|
||||
$world->scheduleDelayedBlockUpdate($pos, 1);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -23,9 +23,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\tile;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\block\inventory\HopperInventory;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\world\World;
|
||||
|
||||
class Hopper extends Spawnable implements Container, Nameable{
|
||||
|
||||
@ -37,8 +38,8 @@ class Hopper extends Spawnable implements Container, Nameable{
|
||||
private HopperInventory $inventory;
|
||||
private int $transferCooldown = 0;
|
||||
|
||||
public function __construct(BlockPosition $position){
|
||||
parent::__construct($position);
|
||||
public function __construct(World $world, Vector3 $pos){
|
||||
parent::__construct($world, $pos);
|
||||
$this->inventory = new HopperInventory($this->position);
|
||||
}
|
||||
|
||||
|
@ -23,12 +23,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\tile;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\FloatTag;
|
||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||
use pocketmine\world\World;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
@ -43,9 +44,9 @@ class ItemFrame extends Spawnable{
|
||||
private int $itemRotation = 0;
|
||||
private float $itemDropChance = 1.0;
|
||||
|
||||
public function __construct(BlockPosition $position){
|
||||
public function __construct(World $world, Vector3 $pos){
|
||||
$this->item = VanillaItems::AIR();
|
||||
parent::__construct($position);
|
||||
parent::__construct($world, $pos);
|
||||
}
|
||||
|
||||
public function readSaveData(CompoundTag $nbt) : void{
|
||||
|
@ -65,6 +65,6 @@ class Jukebox extends Spawnable{
|
||||
}
|
||||
|
||||
protected function onBlockDestroyedHook() : void{
|
||||
$this->position->getWorld()->addSound($this->position->center(), new RecordStopSound());
|
||||
$this->position->getWorld()->addSound($this->position, new RecordStopSound());
|
||||
}
|
||||
}
|
||||
|
@ -23,11 +23,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\tile;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\block\inventory\ShulkerBoxInventory;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\world\World;
|
||||
|
||||
class ShulkerBox extends Spawnable implements Container, Nameable{
|
||||
use NameableTrait {
|
||||
@ -41,8 +42,8 @@ class ShulkerBox extends Spawnable implements Container, Nameable{
|
||||
|
||||
protected ShulkerBoxInventory $inventory;
|
||||
|
||||
public function __construct(BlockPosition $position){
|
||||
parent::__construct($position);
|
||||
public function __construct(World $world, Vector3 $pos){
|
||||
parent::__construct($world, $pos);
|
||||
$this->inventory = new ShulkerBoxInventory($this->position);
|
||||
}
|
||||
|
||||
|
@ -23,14 +23,15 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\tile;
|
||||
|
||||
use pocketmine\block\BlockPosition;
|
||||
use pocketmine\block\utils\SignText;
|
||||
use pocketmine\color\Color;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\ByteTag;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\world\World;
|
||||
use function array_pad;
|
||||
use function array_slice;
|
||||
use function explode;
|
||||
@ -71,9 +72,9 @@ class Sign extends Spawnable{
|
||||
|
||||
protected ?int $editorEntityRuntimeId = null;
|
||||
|
||||
public function __construct(BlockPosition $position){
|
||||
public function __construct(World $world, Vector3 $pos){
|
||||
$this->text = new SignText();
|
||||
parent::__construct($position);
|
||||
parent::__construct($world, $pos);
|
||||
}
|
||||
|
||||
private function readTextTag(CompoundTag $nbt, bool $lightingBugResolved) : void{
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user