mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-04-21 16:24:05 +00:00
Merge branch 'minor-next' into major-next
This commit is contained in:
commit
d4d7d02067
14
.github/workflows/build-docker-image.yml
vendored
14
.github/workflows/build-docker-image.yml
vendored
@ -12,16 +12,16 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@ -53,7 +53,7 @@ jobs:
|
||||
run: echo NAME=$(echo "${GITHUB_REPOSITORY,,}") >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build image for tag
|
||||
uses: docker/build-push-action@v4.1.1
|
||||
uses: docker/build-push-action@v5.0.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@v4.1.1
|
||||
uses: docker/build-push-action@v5.0.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@v4.1.1
|
||||
uses: docker/build-push-action@v5.0.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@v4.1.1
|
||||
uses: docker/build-push-action@v5.0.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
|
2
.github/workflows/discord-release-notify.yml
vendored
2
.github/workflows/discord-release-notify.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.25.5
|
||||
uses: shivammathur/setup-php@2.26.0
|
||||
with:
|
||||
php-version: 8.1
|
||||
|
||||
|
2
.github/workflows/draft-release.yml
vendored
2
.github/workflows/draft-release.yml
vendored
@ -20,7 +20,7 @@ jobs:
|
||||
submodules: true
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@2.25.5
|
||||
uses: shivammathur/setup-php@2.26.0
|
||||
with:
|
||||
php-version: ${{ matrix.php-version }}
|
||||
|
||||
|
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@ -173,7 +173,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.25.5
|
||||
uses: shivammathur/setup-php@2.26.0
|
||||
with:
|
||||
php-version: 8.1
|
||||
tools: php-cs-fixer:3.17
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 3331f8c0d50075eee250ac4b3a8517a12186137a
|
||||
Subproject commit a34e48e7da753b633ffaa4a4f9516eae4bb97baa
|
@ -52,10 +52,10 @@
|
||||
"symfony/filesystem": "~6.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.10.35",
|
||||
"phpstan/phpstan": "1.10.38",
|
||||
"phpstan/phpstan-phpunit": "^1.1.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.2.0",
|
||||
"phpunit/phpunit": "^10.1"
|
||||
"phpunit/phpunit": "~10.3.0 || ~10.2.0 || ~10.1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
76
composer.lock
generated
76
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": "2028bfaf32594237de07fc60f68df728",
|
||||
"content-hash": "2282bf7835c1ced757460b083813e092",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/json-comment",
|
||||
@ -148,16 +148,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-data",
|
||||
"version": "2.5.0+bedrock-1.20.30",
|
||||
"version": "2.5.1+bedrock-1.20.30",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockData.git",
|
||||
"reference": "e920209393a8bf6cb15fb40c3f3149aaf8e1a2b9"
|
||||
"reference": "8f9d96047a731c37b18b28c2bfcdfa2705bb303f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/e920209393a8bf6cb15fb40c3f3149aaf8e1a2b9",
|
||||
"reference": "e920209393a8bf6cb15fb40c3f3149aaf8e1a2b9",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/8f9d96047a731c37b18b28c2bfcdfa2705bb303f",
|
||||
"reference": "8f9d96047a731c37b18b28c2bfcdfa2705bb303f",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -168,9 +168,9 @@
|
||||
"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.20.30"
|
||||
"source": "https://github.com/pmmp/BedrockData/tree/2.5.1+bedrock-1.20.30"
|
||||
},
|
||||
"time": "2023-09-20T16:34:21+00:00"
|
||||
"time": "2023-09-27T11:40:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-item-upgrade-schema",
|
||||
@ -1378,16 +1378,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.10.35",
|
||||
"version": "1.10.38",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "e730e5facb75ffe09dfb229795e8c01a459f26c3"
|
||||
"reference": "5302bb402c57f00fb3c2c015bac86e0827e4b691"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/e730e5facb75ffe09dfb229795e8c01a459f26c3",
|
||||
"reference": "e730e5facb75ffe09dfb229795e8c01a459f26c3",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/5302bb402c57f00fb3c2c015bac86e0827e4b691",
|
||||
"reference": "5302bb402c57f00fb3c2c015bac86e0827e4b691",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1436,20 +1436,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-09-19T15:27:56+00:00"
|
||||
"time": "2023-10-06T14:19:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-phpunit",
|
||||
"version": "1.3.14",
|
||||
"version": "1.3.15",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-phpunit.git",
|
||||
"reference": "614acc10c522e319639bf38b0698a4a566665f04"
|
||||
"reference": "70ecacc64fe8090d8d2a33db5a51fe8e88acd93a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/614acc10c522e319639bf38b0698a4a566665f04",
|
||||
"reference": "614acc10c522e319639bf38b0698a4a566665f04",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/70ecacc64fe8090d8d2a33db5a51fe8e88acd93a",
|
||||
"reference": "70ecacc64fe8090d8d2a33db5a51fe8e88acd93a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1486,9 +1486,9 @@
|
||||
"description": "PHPUnit extensions and rules for PHPStan",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan-phpunit/issues",
|
||||
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.14"
|
||||
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.15"
|
||||
},
|
||||
"time": "2023-08-25T09:46:39+00:00"
|
||||
"time": "2023-10-09T18:58:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-strict-rules",
|
||||
@ -1541,16 +1541,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "10.1.6",
|
||||
"version": "10.1.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "56f33548fe522c8d82da7ff3824b42829d324364"
|
||||
"reference": "355324ca4980b8916c18b9db29f3ef484078f26e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/56f33548fe522c8d82da7ff3824b42829d324364",
|
||||
"reference": "56f33548fe522c8d82da7ff3824b42829d324364",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/355324ca4980b8916c18b9db29f3ef484078f26e",
|
||||
"reference": "355324ca4980b8916c18b9db29f3ef484078f26e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1607,7 +1607,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.6"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.7"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1615,7 +1615,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-09-19T04:59:03+00:00"
|
||||
"time": "2023-10-04T15:34:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
@ -2207,16 +2207,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/complexity",
|
||||
"version": "3.0.1",
|
||||
"version": "3.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/complexity.git",
|
||||
"reference": "c70b73893e10757af9c6a48929fa6a333b56a97a"
|
||||
"reference": "68cfb347a44871f01e33ab0ef8215966432f6957"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/c70b73893e10757af9c6a48929fa6a333b56a97a",
|
||||
"reference": "c70b73893e10757af9c6a48929fa6a333b56a97a",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68cfb347a44871f01e33ab0ef8215966432f6957",
|
||||
"reference": "68cfb347a44871f01e33ab0ef8215966432f6957",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2229,7 +2229,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "3.0-dev"
|
||||
"dev-main": "3.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -2253,7 +2253,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/complexity/issues",
|
||||
"security": "https://github.com/sebastianbergmann/complexity/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/complexity/tree/3.0.1"
|
||||
"source": "https://github.com/sebastianbergmann/complexity/tree/3.1.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2261,7 +2261,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-08-31T09:55:53+00:00"
|
||||
"time": "2023-09-28T11:50:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
@ -2396,16 +2396,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/exporter",
|
||||
"version": "5.1.0",
|
||||
"version": "5.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/exporter.git",
|
||||
"reference": "c3fa8483f9539b190f7cd4bfc4a07631dd1df344"
|
||||
"reference": "64f51654862e0f5e318db7e9dcc2292c63cdbddc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/c3fa8483f9539b190f7cd4bfc4a07631dd1df344",
|
||||
"reference": "c3fa8483f9539b190f7cd4bfc4a07631dd1df344",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/64f51654862e0f5e318db7e9dcc2292c63cdbddc",
|
||||
"reference": "64f51654862e0f5e318db7e9dcc2292c63cdbddc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2419,7 +2419,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "5.0-dev"
|
||||
"dev-main": "5.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -2462,7 +2462,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/exporter/issues",
|
||||
"security": "https://github.com/sebastianbergmann/exporter/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/exporter/tree/5.1.0"
|
||||
"source": "https://github.com/sebastianbergmann/exporter/tree/5.1.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2470,7 +2470,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-09-18T07:15:37+00:00"
|
||||
"time": "2023-09-24T13:22:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/global-state",
|
||||
|
133
src/block/AmethystCluster.php
Normal file
133
src/block/AmethystCluster.php
Normal file
@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\AmethystTrait;
|
||||
use pocketmine\block\utils\AnyFacingTrait;
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
|
||||
final class AmethystCluster extends Transparent{
|
||||
use AmethystTrait;
|
||||
use AnyFacingTrait;
|
||||
|
||||
public const STAGE_SMALL_BUD = 0;
|
||||
public const STAGE_MEDIUM_BUD = 1;
|
||||
public const STAGE_LARGE_BUD = 2;
|
||||
public const STAGE_CLUSTER = 3;
|
||||
|
||||
private int $stage = self::STAGE_CLUSTER;
|
||||
|
||||
public function describeBlockItemState(RuntimeDataDescriber $w) : void{
|
||||
$w->boundedInt(2, self::STAGE_SMALL_BUD, self::STAGE_CLUSTER, $this->stage);
|
||||
}
|
||||
|
||||
public function getStage() : int{ return $this->stage; }
|
||||
|
||||
public function setStage(int $stage) : self{
|
||||
if($stage < self::STAGE_SMALL_BUD || $stage > self::STAGE_CLUSTER){
|
||||
throw new \InvalidArgumentException("Size must be in range " . self::STAGE_SMALL_BUD . " ... " . self::STAGE_CLUSTER);
|
||||
}
|
||||
$this->stage = $stage;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLightLevel() : int{
|
||||
return match($this->stage){
|
||||
self::STAGE_SMALL_BUD => 1,
|
||||
self::STAGE_MEDIUM_BUD => 2,
|
||||
self::STAGE_LARGE_BUD => 4,
|
||||
self::STAGE_CLUSTER => 5,
|
||||
default => throw new AssumptionFailedError("Invalid stage $this->stage"),
|
||||
};
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
$myAxis = Facing::axis($this->facing);
|
||||
|
||||
$box = AxisAlignedBB::one();
|
||||
foreach([Axis::Y, Axis::Z, Axis::X] as $axis){
|
||||
if($axis === $myAxis){
|
||||
continue;
|
||||
}
|
||||
$box->squash($axis, $this->stage === self::STAGE_SMALL_BUD ? 4 / 16 : 3 / 16);
|
||||
}
|
||||
$box->trim($this->facing, 1 - ($this->stage === self::STAGE_CLUSTER ? 7 / 16 : ($this->stage + 3) / 16));
|
||||
|
||||
return [$box];
|
||||
}
|
||||
|
||||
private function canBeSupportedAt(Block $block, int $facing) : bool{
|
||||
return $block->getAdjacentSupportType($facing) === SupportType::FULL;
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$this->canBeSupportedAt($blockReplace, Facing::opposite($face))){
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->facing = $face;
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(!$this->canBeSupportedAt($this, Facing::opposite($this->facing))){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
}
|
||||
}
|
||||
|
||||
public function isAffectedBySilkTouch() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
if($this->stage === self::STAGE_CLUSTER){
|
||||
return [VanillaItems::AMETHYST_SHARD()->setCount(FortuneDropHelper::weighted($item, min: 4, maxBase: 4))];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getDropsForIncompatibleTool(Item $item) : array{
|
||||
if($this->stage === self::STAGE_CLUSTER){
|
||||
return [VanillaItems::AMETHYST_SHARD()->setCount(FortuneDropHelper::weighted($item, min: 2, maxBase: 2))];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
@ -562,10 +562,10 @@ final class BlockTypeIds{
|
||||
public const WEIGHTED_PRESSURE_PLATE_HEAVY = 10532;
|
||||
public const WEIGHTED_PRESSURE_PLATE_LIGHT = 10533;
|
||||
public const WHEAT = 10534;
|
||||
|
||||
public const BUDDING_AMETHYST = 10535;
|
||||
public const WHITE_TULIP = 10536;
|
||||
public const WOOL = 10537;
|
||||
|
||||
public const AMETHYST_CLUSTER = 10538;
|
||||
public const GLAZED_TERRACOTTA = 10539;
|
||||
public const AMETHYST = 10540;
|
||||
public const ANCIENT_DEBRIS = 10541;
|
||||
@ -737,8 +737,16 @@ final class BlockTypeIds{
|
||||
public const BIG_DRIPLEAF_HEAD = 10707;
|
||||
public const BIG_DRIPLEAF_STEM = 10708;
|
||||
public const PINK_PETALS = 10709;
|
||||
public const CRIMSON_ROOTS = 10710;
|
||||
public const WARPED_ROOTS = 10711;
|
||||
public const CHISELED_BOOKSHELF = 10712;
|
||||
public const TORCHFLOWER = 10713;
|
||||
public const TORCHFLOWER_CROP = 10714;
|
||||
public const PITCHER_PLANT = 10715;
|
||||
public const PITCHER_CROP = 10716;
|
||||
public const DOUBLE_PITCHER_CROP = 10717;
|
||||
|
||||
public const FIRST_UNUSED_BLOCK_ID = 10710;
|
||||
public const FIRST_UNUSED_BLOCK_ID = 10718;
|
||||
|
||||
private static int $nextDynamicId = self::FIRST_UNUSED_BLOCK_ID;
|
||||
|
||||
|
@ -45,7 +45,7 @@ class BrewingStand extends Transparent{
|
||||
protected array $slots = [];
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->brewingStandSlots($this->slots);
|
||||
$w->enumSet($this->slots, BrewingStandSlot::cases());
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
|
68
src/block/BuddingAmethyst.php
Normal file
68
src/block/BuddingAmethyst.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\AmethystTrait;
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use function array_rand;
|
||||
use function mt_rand;
|
||||
|
||||
final class BuddingAmethyst extends Opaque{
|
||||
use AmethystTrait;
|
||||
|
||||
public function ticksRandomly() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
if(mt_rand(1, 5) === 1){
|
||||
$face = Facing::ALL[array_rand(Facing::ALL)];
|
||||
|
||||
$adjacent = $this->getSide($face);
|
||||
//TODO: amethyst buds can spawn in water - we need waterlogging support for this
|
||||
|
||||
$newStage = null;
|
||||
|
||||
if($adjacent->getTypeId() === BlockTypeIds::AIR){
|
||||
$newStage = AmethystCluster::STAGE_SMALL_BUD;
|
||||
}elseif(
|
||||
$adjacent->getTypeId() === BlockTypeIds::AMETHYST_CLUSTER &&
|
||||
$adjacent instanceof AmethystCluster &&
|
||||
$adjacent->getStage() < AmethystCluster::STAGE_CLUSTER &&
|
||||
$adjacent->getFacing() === $face
|
||||
){
|
||||
$newStage = $adjacent->getStage() + 1;
|
||||
}
|
||||
if($newStage !== null){
|
||||
BlockEventHelper::grow($adjacent, VanillaBlocks::AMETHYST_CLUSTER()->setStage($newStage)->setFacing($face), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [];
|
||||
}
|
||||
}
|
@ -95,10 +95,10 @@ class Cactus extends Transparent{
|
||||
}
|
||||
}
|
||||
$this->age = 0;
|
||||
$world->setBlock($this->position, $this);
|
||||
$world->setBlock($this->position, $this, update: false);
|
||||
}else{
|
||||
++$this->age;
|
||||
$world->setBlock($this->position, $this);
|
||||
$world->setBlock($this->position, $this, update: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
134
src/block/ChiseledBookshelf.php
Normal file
134
src/block/ChiseledBookshelf.php
Normal file
@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\tile\ChiseledBookshelf as TileChiseledBookshelf;
|
||||
use pocketmine\block\utils\ChiseledBookshelfSlot;
|
||||
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\item\Book;
|
||||
use pocketmine\item\EnchantedBook;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\WritableBookBase;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use function spl_object_id;
|
||||
|
||||
class ChiseledBookshelf extends Opaque{
|
||||
use HorizontalFacingTrait;
|
||||
use FacesOppositePlacingPlayerTrait;
|
||||
|
||||
/**
|
||||
* @var ChiseledBookshelfSlot[]
|
||||
* @phpstan-var array<int, ChiseledBookshelfSlot>
|
||||
*/
|
||||
private array $slots = [];
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->horizontalFacing($this->facing);
|
||||
$w->enumSet($this->slots, ChiseledBookshelfSlot::cases());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given slot is displayed as occupied.
|
||||
* This doesn't guarantee that there is or isn't a book in the bookshelf's inventory.
|
||||
*/
|
||||
public function hasSlot(ChiseledBookshelfSlot $slot) : bool{
|
||||
return isset($this->slots[spl_object_id($slot)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the given slot is displayed as occupied.
|
||||
*
|
||||
* This doesn't modify the bookshelf's inventory, so you can use this to make invisible
|
||||
* books or display books that aren't actually in the bookshelf.
|
||||
*
|
||||
* To modify the contents of the bookshelf inventory, access the tile inventory.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSlot(ChiseledBookshelfSlot $slot, bool $occupied) : self{
|
||||
if($occupied){
|
||||
$this->slots[spl_object_id($slot)] = $slot;
|
||||
}else{
|
||||
unset($this->slots[spl_object_id($slot)]);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns which slots of the bookshelf are displayed as occupied.
|
||||
* As above, these values do not necessarily reflect the contents of the bookshelf inventory,
|
||||
* although they usually will unless modified by plugins.
|
||||
*
|
||||
* @return ChiseledBookshelfSlot[]
|
||||
* @phpstan-return array<int, ChiseledBookshelfSlot>
|
||||
*/
|
||||
public function getSlots() : array{
|
||||
return $this->slots;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($face !== $this->facing){
|
||||
return false;
|
||||
}
|
||||
|
||||
$x = Facing::axis($face) === Axis::X ? $clickVector->getZ() : $clickVector->getX();
|
||||
$slot = ChiseledBookshelfSlot::fromBlockFaceCoordinates(
|
||||
Facing::isPositive(Facing::rotateY($face, true)) ? 1 - $x : $x,
|
||||
$clickVector->y
|
||||
);
|
||||
$tile = $this->position->getWorld()->getTile($this->position);
|
||||
if(!$tile instanceof TileChiseledBookshelf){
|
||||
return false;
|
||||
}
|
||||
|
||||
$inventory = $tile->getInventory();
|
||||
if(!$inventory->isSlotEmpty($slot->value)){
|
||||
$returnedItems[] = $inventory->getItem($slot->value);
|
||||
$inventory->clear($slot->value);
|
||||
$this->setSlot($slot, false);
|
||||
}elseif($item instanceof WritableBookBase || $item instanceof Book || $item instanceof EnchantedBook){
|
||||
//TODO: type tags like blocks would be better for this
|
||||
$inventory->setItem($slot->value, $item->pop());
|
||||
$this->setSlot($slot, true);
|
||||
}else{
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->position->getWorld()->setBlock($this->position, $this);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function isAffectedBySilkTouch() : bool{
|
||||
return true;
|
||||
}
|
||||
}
|
@ -83,8 +83,6 @@ final class ChorusFlower extends Flowable{
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
}
|
||||
|
||||
public function ticksRandomly() : bool{ return $this->age < self::MAX_AGE; }
|
||||
|
||||
/**
|
||||
* @phpstan-return array{int, bool}
|
||||
*/
|
||||
@ -159,6 +157,8 @@ final class ChorusFlower extends Flowable{
|
||||
return $tx;
|
||||
}
|
||||
|
||||
public function ticksRandomly() : bool{ return $this->age < self::MAX_AGE; }
|
||||
|
||||
public function onRandomTick() : void{
|
||||
$world = $this->position->getWorld();
|
||||
|
||||
|
@ -99,7 +99,7 @@ class CocoaBlock extends Transparent{
|
||||
}
|
||||
|
||||
public function ticksRandomly() : bool{
|
||||
return true;
|
||||
return $this->age < self::MAX_AGE;
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
|
@ -62,7 +62,7 @@ abstract class Crops extends Flowable{
|
||||
}
|
||||
|
||||
public function ticksRandomly() : bool{
|
||||
return true;
|
||||
return $this->age < self::MAX_AGE;
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
|
110
src/block/DoublePitcherCrop.php
Normal file
110
src/block/DoublePitcherCrop.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\AgeableTrait;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\event\block\StructureGrowEvent;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use function mt_rand;
|
||||
|
||||
final class DoublePitcherCrop extends DoublePlant{
|
||||
use AgeableTrait {
|
||||
describeBlockOnlyState as describeAge;
|
||||
}
|
||||
|
||||
public const MAX_AGE = 1;
|
||||
|
||||
public function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
parent::describeBlockOnlyState($w);
|
||||
$this->describeAge($w);
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
if($this->top){
|
||||
return [];
|
||||
}
|
||||
|
||||
//the pod exists only in the bottom half of the plant
|
||||
return [
|
||||
AxisAlignedBB::one()
|
||||
->trim(Facing::UP, 11 / 16)
|
||||
->squash(Axis::X, 3 / 16)
|
||||
->squash(Axis::Z, 3 / 16)
|
||||
->extend(Facing::DOWN, 1 / 16) //presumably this is to correct for farmland being 15/16 of a block tall
|
||||
];
|
||||
}
|
||||
|
||||
private function grow(?Player $player) : bool{
|
||||
if($this->age >= self::MAX_AGE){
|
||||
return false;
|
||||
}
|
||||
|
||||
$bottom = $this->top ? $this->getSide(Facing::DOWN) : $this;
|
||||
$top = $this->top ? $this : $this->getSide(Facing::UP);
|
||||
if($top->getTypeId() !== BlockTypeIds::AIR && !$top->hasSameTypeId($this)){
|
||||
return false;
|
||||
}
|
||||
|
||||
$newState = (clone $this)->setAge($this->age + 1);
|
||||
|
||||
$tx = new BlockTransaction($this->position->getWorld());
|
||||
$tx->addBlock($bottom->position, (clone $newState)->setTop(false));
|
||||
$tx->addBlock($top->position, (clone $newState)->setTop(true));
|
||||
|
||||
$ev = new StructureGrowEvent($bottom, $tx, $player);
|
||||
$ev->call();
|
||||
|
||||
return !$ev->isCancelled() && $tx->apply();
|
||||
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item instanceof Fertilizer && $this->grow($player)){
|
||||
$item->pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ticksRandomly() : bool{
|
||||
return $this->age < self::MAX_AGE && !$this->top;
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
//TODO: the growth speed is influenced by farmland and nearby crops
|
||||
//only the bottom half of the plant can grow randomly
|
||||
if(mt_rand(0, 2) === 0 && !$this->top){
|
||||
$this->grow(null);
|
||||
}
|
||||
}
|
||||
}
|
@ -110,7 +110,7 @@ class Leaves extends Transparent{
|
||||
}
|
||||
|
||||
public function ticksRandomly() : bool{
|
||||
return true;
|
||||
return !$this->noDecay && $this->checkDecay;
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
|
39
src/block/NetherRoots.php
Normal file
39
src/block/NetherRoots.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\StaticSupportTrait;
|
||||
use pocketmine\math\Facing;
|
||||
|
||||
final class NetherRoots extends Flowable{
|
||||
use StaticSupportTrait;
|
||||
|
||||
private function canBeSupportedAt(Block $block) : bool{
|
||||
//TODO: nylium, moss
|
||||
$supportBlock = $block->getSide(Facing::DOWN);
|
||||
return
|
||||
$supportBlock->hasTypeTag(BlockTypeTags::DIRT) ||
|
||||
$supportBlock->hasTypeTag(BlockTypeTags::MUD);
|
||||
}
|
||||
}
|
@ -59,10 +59,6 @@ class NetherVines extends Flowable{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function ticksRandomly() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canClimb() : bool{
|
||||
return true;
|
||||
}
|
||||
@ -98,8 +94,12 @@ class NetherVines extends Flowable{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ticksRandomly() : bool{
|
||||
return $this->age < self::MAX_AGE;
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
if(mt_rand(1, 10) === 1 && $this->age < self::MAX_AGE){
|
||||
if($this->age < self::MAX_AGE && mt_rand(1, 10) === 1){
|
||||
if($this->getSide($this->growthFace)->canBeReplaced()){
|
||||
$this->grow(null);
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ class NetherWartPlant extends Flowable{
|
||||
}
|
||||
|
||||
public function ticksRandomly() : bool{
|
||||
return true;
|
||||
return $this->age < self::MAX_AGE;
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
|
105
src/block/PitcherCrop.php
Normal file
105
src/block/PitcherCrop.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\AgeableTrait;
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\StaticSupportTrait;
|
||||
use pocketmine\event\block\StructureGrowEvent;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use function mt_rand;
|
||||
|
||||
final class PitcherCrop extends Flowable{
|
||||
use AgeableTrait;
|
||||
use StaticSupportTrait;
|
||||
|
||||
public const MAX_AGE = 2;
|
||||
|
||||
private function canBeSupportedAt(Block $block) : bool{
|
||||
return $block->getSide(Facing::DOWN)->getTypeId() === BlockTypeIds::FARMLAND;
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
$widthTrim = $this->age === 0 ? 5 : 3;
|
||||
$heightTrim = $this->age === 0 ? 13 : 11;
|
||||
return [
|
||||
AxisAlignedBB::one()
|
||||
->trim(Facing::UP, $heightTrim / 16)
|
||||
->squash(Axis::X, $widthTrim / 16)
|
||||
->squash(Axis::Z, $widthTrim / 16)
|
||||
->extend(Facing::DOWN, 1 / 16) //presumably this is to correct for farmland being 15/16 of a block tall
|
||||
];
|
||||
}
|
||||
|
||||
private function grow(?Player $player) : bool{
|
||||
if($this->age > self::MAX_AGE){
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->age === self::MAX_AGE){
|
||||
$up = $this->getSide(Facing::UP);
|
||||
if($up->getTypeId() !== BlockTypeIds::AIR){
|
||||
return false;
|
||||
}
|
||||
|
||||
$tx = new BlockTransaction($this->position->getWorld());
|
||||
$tx->addBlock($this->position, VanillaBlocks::DOUBLE_PITCHER_CROP()->setTop(false));
|
||||
$tx->addBlock($this->position->up(), VanillaBlocks::DOUBLE_PITCHER_CROP()->setTop(true));
|
||||
|
||||
$ev = new StructureGrowEvent($this, $tx, $player);
|
||||
$ev->call();
|
||||
|
||||
return !$ev->isCancelled() && $tx->apply();
|
||||
}
|
||||
|
||||
return BlockEventHelper::grow($this, (clone $this)->setAge($this->age + 1), $player);
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item instanceof Fertilizer && $this->grow($player)){
|
||||
$item->pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ticksRandomly() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
//TODO: the growth speed is influenced by farmland and nearby crops
|
||||
if(mt_rand(0, 2) === 0){
|
||||
$this->grow(null);
|
||||
}
|
||||
}
|
||||
}
|
@ -70,7 +70,7 @@ class RedstoneOre extends Opaque{
|
||||
}
|
||||
|
||||
public function ticksRandomly() : bool{
|
||||
return true;
|
||||
return $this->lit;
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
|
@ -102,7 +102,7 @@ class SweetBerryBush extends Flowable{
|
||||
}
|
||||
|
||||
public function ticksRandomly() : bool{
|
||||
return true;
|
||||
return $this->age < self::STAGE_MATURE;
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
|
90
src/block/TorchflowerCrop.php
Normal file
90
src/block/TorchflowerCrop.php
Normal file
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\StaticSupportTrait;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use function mt_rand;
|
||||
|
||||
final class TorchflowerCrop extends Flowable{
|
||||
use StaticSupportTrait;
|
||||
|
||||
private bool $ready = false;
|
||||
|
||||
public function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->bool($this->ready);
|
||||
}
|
||||
|
||||
public function isReady() : bool{ return $this->ready; }
|
||||
|
||||
public function setReady(bool $ready) : self{
|
||||
$this->ready = $ready;
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function canBeSupportedAt(Block $block) : bool{
|
||||
return $block->getSide(Facing::DOWN)->getTypeId() === BlockTypeIds::FARMLAND;
|
||||
}
|
||||
|
||||
private function getNextState() : Block{
|
||||
if($this->ready){
|
||||
return VanillaBlocks::TORCHFLOWER();
|
||||
}else{
|
||||
return VanillaBlocks::TORCHFLOWER_CROP()->setReady(true);
|
||||
}
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item instanceof Fertilizer){
|
||||
if(BlockEventHelper::grow($this, $this->getNextState(), $player)){
|
||||
$item->pop();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ticksRandomly() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
if(mt_rand(0, 2) === 1){
|
||||
BlockEventHelper::grow($this, $this->getNextState(), null);
|
||||
}
|
||||
}
|
||||
|
||||
public function asItem() : Item{
|
||||
return VanillaItems::TORCHFLOWER_SEEDS();
|
||||
}
|
||||
}
|
@ -38,6 +38,7 @@ use pocketmine\block\tile\BlastFurnace as TileBlastFurnace;
|
||||
use pocketmine\block\tile\BrewingStand as TileBrewingStand;
|
||||
use pocketmine\block\tile\Cauldron as TileCauldron;
|
||||
use pocketmine\block\tile\Chest as TileChest;
|
||||
use pocketmine\block\tile\ChiseledBookshelf as TileChiseledBookshelf;
|
||||
use pocketmine\block\tile\Comparator as TileComparator;
|
||||
use pocketmine\block\tile\DaylightSensor as TileDaylightSensor;
|
||||
use pocketmine\block\tile\EnchantTable as TileEnchantingTable;
|
||||
@ -54,19 +55,16 @@ 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\Smoker as TileSmoker;
|
||||
use pocketmine\block\utils\AmethystTrait;
|
||||
use pocketmine\block\utils\LeavesType;
|
||||
use pocketmine\block\utils\SaplingType;
|
||||
use pocketmine\block\utils\WoodType;
|
||||
use pocketmine\crafting\FurnaceType;
|
||||
use pocketmine\entity\projectile\Projectile;
|
||||
use pocketmine\item\enchantment\ItemEnchantmentTags as EnchantmentTags;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ToolTier;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\RayTraceResult;
|
||||
use pocketmine\utils\CloningRegistryTrait;
|
||||
use pocketmine\world\sound\AmethystBlockChimeSound;
|
||||
use pocketmine\world\sound\BlockPunchSound;
|
||||
use function mb_strtolower;
|
||||
use function strtolower;
|
||||
|
||||
@ -96,6 +94,7 @@ use function strtolower;
|
||||
* @method static Flower ALLIUM()
|
||||
* @method static MushroomStem ALL_SIDED_MUSHROOM_STEM()
|
||||
* @method static Opaque AMETHYST()
|
||||
* @method static AmethystCluster AMETHYST_CLUSTER()
|
||||
* @method static Opaque ANCIENT_DEBRIS()
|
||||
* @method static Opaque ANDESITE()
|
||||
* @method static Slab ANDESITE_SLAB()
|
||||
@ -149,6 +148,7 @@ use function strtolower;
|
||||
* @method static Wall BRICK_WALL()
|
||||
* @method static BrownMushroom BROWN_MUSHROOM()
|
||||
* @method static BrownMushroomBlock BROWN_MUSHROOM_BLOCK()
|
||||
* @method static BuddingAmethyst BUDDING_AMETHYST()
|
||||
* @method static Cactus CACTUS()
|
||||
* @method static Cake CAKE()
|
||||
* @method static CakeWithCandle CAKE_WITH_CANDLE()
|
||||
@ -178,6 +178,7 @@ use function strtolower;
|
||||
* @method static WallSign CHERRY_WALL_SIGN()
|
||||
* @method static Wood CHERRY_WOOD()
|
||||
* @method static Chest CHEST()
|
||||
* @method static ChiseledBookshelf CHISELED_BOOKSHELF()
|
||||
* @method static Opaque CHISELED_DEEPSLATE()
|
||||
* @method static Opaque CHISELED_NETHER_BRICKS()
|
||||
* @method static Opaque CHISELED_POLISHED_BLACKSTONE()
|
||||
@ -222,6 +223,7 @@ use function strtolower;
|
||||
* @method static Wood CRIMSON_HYPHAE()
|
||||
* @method static Planks CRIMSON_PLANKS()
|
||||
* @method static WoodenPressurePlate CRIMSON_PRESSURE_PLATE()
|
||||
* @method static NetherRoots CRIMSON_ROOTS()
|
||||
* @method static FloorSign CRIMSON_SIGN()
|
||||
* @method static WoodenSlab CRIMSON_SLAB()
|
||||
* @method static WoodenStairs CRIMSON_STAIRS()
|
||||
@ -282,6 +284,7 @@ use function strtolower;
|
||||
* @method static Stair DIORITE_STAIRS()
|
||||
* @method static Wall DIORITE_WALL()
|
||||
* @method static Dirt DIRT()
|
||||
* @method static DoublePitcherCrop DOUBLE_PITCHER_CROP()
|
||||
* @method static DoubleTallGrass DOUBLE_TALLGRASS()
|
||||
* @method static DragonEgg DRAGON_EGG()
|
||||
* @method static DriedKelp DRIED_KELP()
|
||||
@ -577,6 +580,8 @@ use function strtolower;
|
||||
* @method static DoublePlant PEONY()
|
||||
* @method static PinkPetals PINK_PETALS()
|
||||
* @method static Flower PINK_TULIP()
|
||||
* @method static PitcherCrop PITCHER_CROP()
|
||||
* @method static DoublePlant PITCHER_PLANT()
|
||||
* @method static Podzol PODZOL()
|
||||
* @method static Opaque POLISHED_ANDESITE()
|
||||
* @method static Slab POLISHED_ANDESITE_SLAB()
|
||||
@ -724,6 +729,8 @@ use function strtolower;
|
||||
* @method static TintedGlass TINTED_GLASS()
|
||||
* @method static TNT TNT()
|
||||
* @method static Torch TORCH()
|
||||
* @method static Flower TORCHFLOWER()
|
||||
* @method static TorchflowerCrop TORCHFLOWER_CROP()
|
||||
* @method static TrappedChest TRAPPED_CHEST()
|
||||
* @method static Tripwire TRIPWIRE()
|
||||
* @method static TripwireHook TRIPWIRE_HOOK()
|
||||
@ -740,6 +747,7 @@ use function strtolower;
|
||||
* @method static Wood WARPED_HYPHAE()
|
||||
* @method static Planks WARPED_PLANKS()
|
||||
* @method static WoodenPressurePlate WARPED_PRESSURE_PLATE()
|
||||
* @method static NetherRoots WARPED_ROOTS()
|
||||
* @method static FloorSign WARPED_SIGN()
|
||||
* @method static WoodenSlab WARPED_SLAB()
|
||||
* @method static WoodenStairs WARPED_STAIRS()
|
||||
@ -808,6 +816,7 @@ final class VanillaBlocks{
|
||||
self::register("blue_ice", new BlueIce(new BID(Ids::BLUE_ICE), "Blue Ice", new Info(BreakInfo::pickaxe(2.8))));
|
||||
self::register("bone_block", new BoneBlock(new BID(Ids::BONE_BLOCK), "Bone Block", new Info(BreakInfo::pickaxe(2.0, ToolTier::WOOD))));
|
||||
self::register("bookshelf", new Bookshelf(new BID(Ids::BOOKSHELF), "Bookshelf", new Info(BreakInfo::axe(1.5))));
|
||||
self::register("chiseled_bookshelf", new ChiseledBookshelf(new BID(Ids::CHISELED_BOOKSHELF, TileChiseledBookshelf::class), "Chiseled Bookshelf", new Info(BreakInfo::axe(1.5))));
|
||||
self::register("brewing_stand", new BrewingStand(new BID(Ids::BREWING_STAND, TileBrewingStand::class), "Brewing Stand", new Info(BreakInfo::pickaxe(0.5, ToolTier::WOOD))));
|
||||
|
||||
$bricksBreakInfo = new Info(BreakInfo::pickaxe(2.0, ToolTier::WOOD, 30.0));
|
||||
@ -846,6 +855,9 @@ final class VanillaBlocks{
|
||||
self::register("pink_petals", new PinkPetals(new BID(Ids::PINK_PETALS), "Pink Petals", new Info(BreakInfo::instant())));
|
||||
self::register("double_tallgrass", new DoubleTallGrass(new BID(Ids::DOUBLE_TALLGRASS), "Double Tallgrass", new Info(BreakInfo::instant(ToolType::SHEARS, 1))));
|
||||
self::register("large_fern", new DoubleTallGrass(new BID(Ids::LARGE_FERN), "Large Fern", new Info(BreakInfo::instant(ToolType::SHEARS, 1))));
|
||||
self::register("pitcher_plant", new DoublePlant(new BID(Ids::PITCHER_PLANT), "Pitcher Plant", new Info(BreakInfo::instant())));
|
||||
self::register("pitcher_crop", new PitcherCrop(new BID(Ids::PITCHER_CROP), "Pitcher Crop", new Info(BreakInfo::instant())));
|
||||
self::register("double_pitcher_crop", new DoublePitcherCrop(new BID(Ids::DOUBLE_PITCHER_CROP), "Double Pitcher Crop", new Info(BreakInfo::instant())));
|
||||
self::register("dragon_egg", new DragonEgg(new BID(Ids::DRAGON_EGG), "Dragon Egg", new Info(BreakInfo::pickaxe(3.0, ToolTier::WOOD))));
|
||||
self::register("dried_kelp", new DriedKelp(new BID(Ids::DRIED_KELP), "Dried Kelp Block", new Info(new BreakInfo(0.5, ToolType::NONE, 0, 12.5))));
|
||||
self::register("emerald", new Opaque(new BID(Ids::EMERALD), "Emerald Block", new Info(BreakInfo::pickaxe(5.0, ToolTier::IRON, 30.0))));
|
||||
@ -875,6 +887,8 @@ final class VanillaBlocks{
|
||||
self::register("pink_tulip", new Flower(new BID(Ids::PINK_TULIP), "Pink Tulip", $flowerTypeInfo));
|
||||
self::register("red_tulip", new Flower(new BID(Ids::RED_TULIP), "Red Tulip", $flowerTypeInfo));
|
||||
self::register("white_tulip", new Flower(new BID(Ids::WHITE_TULIP), "White Tulip", $flowerTypeInfo));
|
||||
self::register("torchflower", new Flower(new BID(Ids::TORCHFLOWER), "Torchflower", $flowerTypeInfo));
|
||||
self::register("torchflower_crop", new TorchflowerCrop(new BID(Ids::TORCHFLOWER_CROP), "Torchflower Crop", new Info(BreakInfo::instant())));
|
||||
self::register("flower_pot", new FlowerPot(new BID(Ids::FLOWER_POT, TileFlowerPot::class), "Flower Pot", new Info(BreakInfo::instant())));
|
||||
self::register("frosted_ice", new FrostedIce(new BID(Ids::FROSTED_ICE), "Frosted Ice", new Info(BreakInfo::pickaxe(2.5))));
|
||||
self::register("furnace", new Furnace(new BID(Ids::FURNACE, TileNormalFurnace::class), "Furnace", new Info(BreakInfo::pickaxe(3.5, ToolTier::WOOD)), FurnaceType::FURNACE));
|
||||
@ -1535,17 +1549,21 @@ final class VanillaBlocks{
|
||||
self::register("twisting_vines", new NetherVines(new BID(Ids::TWISTING_VINES), "Twisting Vines", new Info(BreakInfo::instant()), Facing::UP));
|
||||
self::register("weeping_vines", new NetherVines(new BID(Ids::WEEPING_VINES), "Weeping Vines", new Info(BreakInfo::instant()), Facing::DOWN));
|
||||
|
||||
$netherRootsInfo = new Info(BreakInfo::instant(), [Tags::POTTABLE_PLANTS]);
|
||||
self::register("crimson_roots", new NetherRoots(new BID(Ids::CRIMSON_ROOTS), "Crimson Roots", $netherRootsInfo));
|
||||
self::register("warped_roots", new NetherRoots(new BID(Ids::WARPED_ROOTS), "Warped Roots", $netherRootsInfo));
|
||||
|
||||
self::register("chain", new Chain(new BID(Ids::CHAIN), "Chain", new Info(BreakInfo::pickaxe(5.0, ToolTier::WOOD))));
|
||||
}
|
||||
|
||||
private static function registerBlocksR17() : void{
|
||||
//in java this can be acquired using any tool - seems to be a parity issue in bedrock
|
||||
self::register("amethyst", new class(new BID(Ids::AMETHYST), "Amethyst", new Info(BreakInfo::pickaxe(1.5, ToolTier::WOOD))) extends Opaque{
|
||||
public function onProjectileHit(Projectile $projectile, RayTraceResult $hitResult) : void{
|
||||
$this->position->getWorld()->addSound($this->position, new AmethystBlockChimeSound());
|
||||
$this->position->getWorld()->addSound($this->position, new BlockPunchSound($this));
|
||||
}
|
||||
$amethystInfo = new Info(BreakInfo::pickaxe(1.5, ToolTier::WOOD));
|
||||
self::register("amethyst", new class(new BID(Ids::AMETHYST), "Amethyst", $amethystInfo) extends Opaque{
|
||||
use AmethystTrait;
|
||||
});
|
||||
self::register("budding_amethyst", new BuddingAmethyst(new BID(Ids::BUDDING_AMETHYST), "Budding Amethyst", $amethystInfo));
|
||||
self::register("amethyst_cluster", new AmethystCluster(new BID(Ids::AMETHYST_CLUSTER), "Amethyst Cluster", $amethystInfo));
|
||||
|
||||
self::register("calcite", new Opaque(new BID(Ids::CALCITE), "Calcite", new Info(BreakInfo::pickaxe(0.75, ToolTier::WOOD))));
|
||||
self::register("tuff", new Opaque(new BID(Ids::TUFF), "Tuff", new Info(BreakInfo::pickaxe(1.5, ToolTier::WOOD, 30.0))));
|
||||
|
58
src/block/tile/ChiseledBookshelf.php
Normal file
58
src/block/tile/ChiseledBookshelf.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\tile;
|
||||
|
||||
use pocketmine\block\utils\ChiseledBookshelfSlot;
|
||||
use pocketmine\inventory\SimpleInventory;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\world\World;
|
||||
use function count;
|
||||
|
||||
class ChiseledBookshelf extends Tile implements Container{
|
||||
use ContainerTrait;
|
||||
|
||||
private SimpleInventory $inventory;
|
||||
|
||||
public function __construct(World $world, Vector3 $pos){
|
||||
parent::__construct($world, $pos);
|
||||
$this->inventory = new SimpleInventory(count(ChiseledBookshelfSlot::cases()));
|
||||
}
|
||||
|
||||
public function getInventory() : SimpleInventory{
|
||||
return $this->inventory;
|
||||
}
|
||||
|
||||
public function getRealInventory() : SimpleInventory{
|
||||
return $this->inventory;
|
||||
}
|
||||
|
||||
public function readSaveData(CompoundTag $nbt) : void{
|
||||
$this->loadItems($nbt);
|
||||
}
|
||||
|
||||
public function writeSaveData(CompoundTag $nbt) : void{
|
||||
$this->saveItems($nbt);
|
||||
}
|
||||
}
|
@ -59,6 +59,7 @@ final class TileFactory{
|
||||
$this->register(BrewingStand::class, ["BrewingStand", "minecraft:brewing_stand"]);
|
||||
$this->register(Cauldron::class, ["Cauldron", "minecraft:cauldron"]);
|
||||
$this->register(Chest::class, ["Chest", "minecraft:chest"]);
|
||||
$this->register(ChiseledBookshelf::class, ["ChiseledBookshelf", "minecraft:chiseled_bookshelf"]);
|
||||
$this->register(Comparator::class, ["Comparator", "minecraft:comparator"]);
|
||||
$this->register(DaylightSensor::class, ["DaylightDetector", "minecraft:daylight_detector"]);
|
||||
$this->register(EnchantTable::class, ["EnchantTable", "minecraft:enchanting_table"]);
|
||||
|
@ -24,7 +24,6 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use function ceil;
|
||||
use function log;
|
||||
|
||||
/**
|
||||
@ -35,7 +34,7 @@ trait AgeableTrait{
|
||||
protected int $age = 0;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->boundedInt((int) ceil(log(self::MAX_AGE, 2)), 0, self::MAX_AGE, $this->age);
|
||||
$w->boundedInt(((int) log(self::MAX_AGE, 2)) + 1, 0, self::MAX_AGE, $this->age);
|
||||
}
|
||||
|
||||
public function getAge() : int{ return $this->age; }
|
||||
|
40
src/block/utils/AmethystTrait.php
Normal file
40
src/block/utils/AmethystTrait.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?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\utils;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\entity\projectile\Projectile;
|
||||
use pocketmine\math\RayTraceResult;
|
||||
use pocketmine\world\sound\AmethystBlockChimeSound;
|
||||
use pocketmine\world\sound\BlockPunchSound;
|
||||
|
||||
trait AmethystTrait{
|
||||
/**
|
||||
* @see Block::onProjectileHit()
|
||||
*/
|
||||
public function onProjectileHit(Projectile $projectile, RayTraceResult $hitResult) : void{
|
||||
$this->position->getWorld()->addSound($this->position, new AmethystBlockChimeSound());
|
||||
$this->position->getWorld()->addSound($this->position, new BlockPunchSound($this));
|
||||
}
|
||||
}
|
53
src/block/utils/ChiseledBookshelfSlot.php
Normal file
53
src/block/utils/ChiseledBookshelfSlot.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
enum ChiseledBookshelfSlot : int{
|
||||
case TOP_LEFT = 0;
|
||||
case TOP_MIDDLE = 1;
|
||||
case TOP_RIGHT = 2;
|
||||
case BOTTOM_LEFT = 3;
|
||||
case BOTTOM_MIDDLE = 4;
|
||||
case BOTTOM_RIGHT = 5;
|
||||
|
||||
private const SLOTS_PER_SHELF = 3;
|
||||
|
||||
public static function fromBlockFaceCoordinates(float $x, float $y) : self{
|
||||
if($x < 0 || $x > 1){
|
||||
throw new \InvalidArgumentException("X must be between 0 and 1, got $x");
|
||||
}
|
||||
if($y < 0 || $y > 1){
|
||||
throw new \InvalidArgumentException("Y must be between 0 and 1, got $y");
|
||||
}
|
||||
|
||||
$slot = ($y < 0.5 ? self::SLOTS_PER_SHELF : 0) + match(true){
|
||||
//we can't use simple maths here as the action is aligned to the 16x16 pixel grid :(
|
||||
$x < 6 / 16 => 0,
|
||||
$x < 11 / 16 => 1,
|
||||
default => 2
|
||||
};
|
||||
|
||||
return self::from($slot);
|
||||
}
|
||||
}
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\data\bedrock\block\convert;
|
||||
|
||||
use pocketmine\block\ActivatorRail;
|
||||
use pocketmine\block\AmethystCluster;
|
||||
use pocketmine\block\Anvil;
|
||||
use pocketmine\block\Bamboo;
|
||||
use pocketmine\block\BambooSapling;
|
||||
@ -50,6 +51,7 @@ use pocketmine\block\CaveVines;
|
||||
use pocketmine\block\Chain;
|
||||
use pocketmine\block\ChemistryTable;
|
||||
use pocketmine\block\Chest;
|
||||
use pocketmine\block\ChiseledBookshelf;
|
||||
use pocketmine\block\ChorusFlower;
|
||||
use pocketmine\block\CocoaBlock;
|
||||
use pocketmine\block\Concrete;
|
||||
@ -63,6 +65,7 @@ use pocketmine\block\DaylightSensor;
|
||||
use pocketmine\block\DetectorRail;
|
||||
use pocketmine\block\Dirt;
|
||||
use pocketmine\block\Door;
|
||||
use pocketmine\block\DoublePitcherCrop;
|
||||
use pocketmine\block\DoublePlant;
|
||||
use pocketmine\block\DoubleTallGrass;
|
||||
use pocketmine\block\DyedCandle;
|
||||
@ -101,6 +104,7 @@ use pocketmine\block\NetherPortal;
|
||||
use pocketmine\block\NetherVines;
|
||||
use pocketmine\block\NetherWartPlant;
|
||||
use pocketmine\block\PinkPetals;
|
||||
use pocketmine\block\PitcherCrop;
|
||||
use pocketmine\block\Potato;
|
||||
use pocketmine\block\PoweredRail;
|
||||
use pocketmine\block\PumpkinStem;
|
||||
@ -134,6 +138,7 @@ use pocketmine\block\Sugarcane;
|
||||
use pocketmine\block\SweetBerryBush;
|
||||
use pocketmine\block\TNT;
|
||||
use pocketmine\block\Torch;
|
||||
use pocketmine\block\TorchflowerCrop;
|
||||
use pocketmine\block\Trapdoor;
|
||||
use pocketmine\block\TrappedChest;
|
||||
use pocketmine\block\Tripwire;
|
||||
@ -717,6 +722,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->mapSimple(Blocks::BOOKSHELF(), Ids::BOOKSHELF);
|
||||
$this->mapSimple(Blocks::BRICKS(), Ids::BRICK_BLOCK);
|
||||
$this->mapSimple(Blocks::BROWN_MUSHROOM(), Ids::BROWN_MUSHROOM);
|
||||
$this->mapSimple(Blocks::BUDDING_AMETHYST(), Ids::BUDDING_AMETHYST);
|
||||
$this->mapSimple(Blocks::CALCITE(), Ids::CALCITE);
|
||||
$this->mapSimple(Blocks::CARTOGRAPHY_TABLE(), Ids::CARTOGRAPHY_TABLE);
|
||||
$this->mapSimple(Blocks::CHEMICAL_HEAT(), Ids::CHEMICAL_HEAT);
|
||||
@ -736,6 +742,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->mapSimple(Blocks::CRACKED_NETHER_BRICKS(), Ids::CRACKED_NETHER_BRICKS);
|
||||
$this->mapSimple(Blocks::CRACKED_POLISHED_BLACKSTONE_BRICKS(), Ids::CRACKED_POLISHED_BLACKSTONE_BRICKS);
|
||||
$this->mapSimple(Blocks::CRAFTING_TABLE(), Ids::CRAFTING_TABLE);
|
||||
$this->mapSimple(Blocks::CRIMSON_ROOTS(), Ids::CRIMSON_ROOTS);
|
||||
$this->mapSimple(Blocks::CRYING_OBSIDIAN(), Ids::CRYING_OBSIDIAN);
|
||||
$this->mapSimple(Blocks::DANDELION(), Ids::YELLOW_FLOWER);
|
||||
$this->mapSimple(Blocks::DEAD_BUSH(), Ids::DEADBUSH);
|
||||
@ -950,8 +957,10 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->mapSimple(Blocks::SOUL_SOIL(), Ids::SOUL_SOIL);
|
||||
$this->mapSimple(Blocks::SPORE_BLOSSOM(), Ids::SPORE_BLOSSOM);
|
||||
$this->mapSimple(Blocks::TINTED_GLASS(), Ids::TINTED_GLASS);
|
||||
$this->mapSimple(Blocks::TORCHFLOWER(), Ids::TORCHFLOWER);
|
||||
$this->mapSimple(Blocks::TUFF(), Ids::TUFF);
|
||||
$this->mapSimple(Blocks::WARPED_WART_BLOCK(), Ids::WARPED_WART_BLOCK);
|
||||
$this->mapSimple(Blocks::WARPED_ROOTS(), Ids::WARPED_ROOTS);
|
||||
$this->mapSimple(Blocks::WITHER_ROSE(), Ids::WITHER_ROSE);
|
||||
}
|
||||
|
||||
@ -965,6 +974,16 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->map(Blocks::ALLIUM(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_ALLIUM));
|
||||
$this->map(Blocks::ALL_SIDED_MUSHROOM_STEM(), fn() => Writer::create(Ids::BROWN_MUSHROOM_BLOCK)
|
||||
->writeInt(StateNames::HUGE_MUSHROOM_BITS, BlockLegacyMetadata::MUSHROOM_BLOCK_ALL_STEM));
|
||||
$this->map(Blocks::AMETHYST_CLUSTER(), fn(AmethystCluster $block) => Writer::create(
|
||||
match($stage = $block->getStage()){
|
||||
AmethystCluster::STAGE_SMALL_BUD => Ids::SMALL_AMETHYST_BUD,
|
||||
AmethystCluster::STAGE_MEDIUM_BUD => Ids::MEDIUM_AMETHYST_BUD,
|
||||
AmethystCluster::STAGE_LARGE_BUD => Ids::LARGE_AMETHYST_BUD,
|
||||
AmethystCluster::STAGE_CLUSTER => Ids::AMETHYST_CLUSTER,
|
||||
default => throw new BlockStateSerializeException("Invalid Amethyst Cluster stage $stage"),
|
||||
})
|
||||
->writeBlockFace($block->getFacing())
|
||||
);
|
||||
$this->map(Blocks::ANDESITE(), fn() => Helper::encodeStone(StringValues::STONE_TYPE_ANDESITE));
|
||||
$this->map(Blocks::ANDESITE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab3($block, StringValues::STONE_SLAB_TYPE_3_ANDESITE));
|
||||
$this->map(Blocks::ANDESITE_STAIRS(), fn(Stair $block) => Helper::encodeStairs($block, new Writer(Ids::ANDESITE_STAIRS)));
|
||||
@ -1100,6 +1119,15 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
return Writer::create(Ids::CHEST)
|
||||
->writeHorizontalFacing($block->getFacing());
|
||||
});
|
||||
$this->map(Blocks::CHISELED_BOOKSHELF(), function(ChiseledBookshelf $block) : Writer{
|
||||
$flags = 0;
|
||||
foreach($block->getSlots() as $slot){
|
||||
$flags |= 1 << $slot->value;
|
||||
}
|
||||
return Writer::create(Ids::CHISELED_BOOKSHELF)
|
||||
->writeLegacyHorizontalFacing($block->getFacing())
|
||||
->writeInt(StateNames::BOOKS_STORED, $flags);
|
||||
});
|
||||
$this->map(Blocks::CHISELED_QUARTZ(), fn(SimplePillar $block) => Helper::encodeQuartz(StringValues::CHISEL_TYPE_CHISELED, $block->getAxis()));
|
||||
$this->map(Blocks::CHISELED_RED_SANDSTONE(), fn() => Helper::encodeSandstone(Ids::RED_SANDSTONE, StringValues::SAND_STONE_TYPE_HEIROGLYPHS));
|
||||
$this->map(Blocks::CHISELED_SANDSTONE(), fn() => Helper::encodeSandstone(Ids::SANDSTONE, StringValues::SAND_STONE_TYPE_HEIROGLYPHS));
|
||||
@ -1430,6 +1458,20 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
->writeInt(StateNames::GROWTH, $block->getCount() - 1);
|
||||
});
|
||||
$this->map(Blocks::PINK_TULIP(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_TULIP_PINK));
|
||||
$this->map(Blocks::PITCHER_PLANT(), function(DoublePlant $block) : Writer{
|
||||
return Writer::create(Ids::PITCHER_PLANT)
|
||||
->writeBool(StateNames::UPPER_BLOCK_BIT, $block->isTop());
|
||||
});
|
||||
$this->map(Blocks::PITCHER_CROP(), function(PitcherCrop $block) : Writer{
|
||||
return Writer::create(Ids::PITCHER_CROP)
|
||||
->writeInt(StateNames::GROWTH, $block->getAge())
|
||||
->writeBool(StateNames::UPPER_BLOCK_BIT, false);
|
||||
});
|
||||
$this->map(Blocks::DOUBLE_PITCHER_CROP(), function(DoublePitcherCrop $block) : Writer{
|
||||
return Writer::create(Ids::PITCHER_CROP)
|
||||
->writeInt(StateNames::GROWTH, $block->getAge() + 1 + PitcherCrop::MAX_AGE)
|
||||
->writeBool(StateNames::UPPER_BLOCK_BIT, $block->isTop());
|
||||
});
|
||||
$this->map(Blocks::POLISHED_ANDESITE(), fn() => Helper::encodeStone(StringValues::STONE_TYPE_ANDESITE_SMOOTH));
|
||||
$this->map(Blocks::POLISHED_ANDESITE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab3($block, StringValues::STONE_SLAB_TYPE_3_POLISHED_ANDESITE));
|
||||
$this->mapStairs(Blocks::POLISHED_ANDESITE_STAIRS(), Ids::POLISHED_ANDESITE_STAIRS);
|
||||
@ -1618,6 +1660,10 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
return Writer::create(Ids::TORCH)
|
||||
->writeTorchFacing($block->getFacing());
|
||||
});
|
||||
$this->map(Blocks::TORCHFLOWER_CROP(), function(TorchflowerCrop $block){
|
||||
return Writer::create(Ids::TORCHFLOWER_CROP)
|
||||
->writeInt(StateNames::GROWTH, $block->isReady() ? 1 : 0);
|
||||
});
|
||||
$this->map(Blocks::TRAPPED_CHEST(), function(TrappedChest $block) : Writer{
|
||||
return Writer::create(Ids::TRAPPED_CHEST)
|
||||
->writeHorizontalFacing($block->getFacing());
|
||||
|
@ -135,6 +135,19 @@ final class BlockStateReader{
|
||||
]);
|
||||
}
|
||||
|
||||
/** @throws BlockStateDeserializeException */
|
||||
public function readBlockFace() : int{
|
||||
return match($raw = $this->readString(BlockStateNames::MC_BLOCK_FACE)){
|
||||
StringValues::MC_BLOCK_FACE_DOWN => Facing::DOWN,
|
||||
StringValues::MC_BLOCK_FACE_UP => Facing::UP,
|
||||
StringValues::MC_BLOCK_FACE_NORTH => Facing::NORTH,
|
||||
StringValues::MC_BLOCK_FACE_SOUTH => Facing::SOUTH,
|
||||
StringValues::MC_BLOCK_FACE_WEST => Facing::WEST,
|
||||
StringValues::MC_BLOCK_FACE_EAST => Facing::EAST,
|
||||
default => throw $this->badValueException(BlockStateNames::MC_BLOCK_FACE, $raw)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int[]
|
||||
* @phpstan-return array<int, int>
|
||||
|
@ -23,16 +23,20 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\data\bedrock\block\convert;
|
||||
|
||||
use pocketmine\block\AmethystCluster;
|
||||
use pocketmine\block\Bamboo;
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\CaveVines;
|
||||
use pocketmine\block\ChorusFlower;
|
||||
use pocketmine\block\DoublePitcherCrop;
|
||||
use pocketmine\block\Light;
|
||||
use pocketmine\block\PinkPetals;
|
||||
use pocketmine\block\PitcherCrop;
|
||||
use pocketmine\block\Slab;
|
||||
use pocketmine\block\Stair;
|
||||
use pocketmine\block\SweetBerryBush;
|
||||
use pocketmine\block\utils\BrewingStandSlot;
|
||||
use pocketmine\block\utils\ChiseledBookshelfSlot;
|
||||
use pocketmine\block\utils\CopperOxidation;
|
||||
use pocketmine\block\utils\CoralType;
|
||||
use pocketmine\block\utils\DirtType;
|
||||
@ -611,6 +615,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->mapSimple(Ids::BOOKSHELF, fn() => Blocks::BOOKSHELF());
|
||||
$this->mapSimple(Ids::BRICK_BLOCK, fn() => Blocks::BRICKS());
|
||||
$this->mapSimple(Ids::BROWN_MUSHROOM, fn() => Blocks::BROWN_MUSHROOM());
|
||||
$this->mapSimple(Ids::BUDDING_AMETHYST, fn() => Blocks::BUDDING_AMETHYST());
|
||||
$this->mapSimple(Ids::CALCITE, fn() => Blocks::CALCITE());
|
||||
$this->mapSimple(Ids::CARTOGRAPHY_TABLE, fn() => Blocks::CARTOGRAPHY_TABLE());
|
||||
$this->mapSimple(Ids::CHEMICAL_HEAT, fn() => Blocks::CHEMICAL_HEAT());
|
||||
@ -629,6 +634,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->mapSimple(Ids::CRACKED_NETHER_BRICKS, fn() => Blocks::CRACKED_NETHER_BRICKS());
|
||||
$this->mapSimple(Ids::CRACKED_POLISHED_BLACKSTONE_BRICKS, fn() => Blocks::CRACKED_POLISHED_BLACKSTONE_BRICKS());
|
||||
$this->mapSimple(Ids::CRAFTING_TABLE, fn() => Blocks::CRAFTING_TABLE());
|
||||
$this->mapSimple(Ids::CRIMSON_ROOTS, fn() => Blocks::CRIMSON_ROOTS());
|
||||
$this->mapSimple(Ids::CRYING_OBSIDIAN, fn() => Blocks::CRYING_OBSIDIAN());
|
||||
$this->mapSimple(Ids::DEADBUSH, fn() => Blocks::DEAD_BUSH());
|
||||
$this->mapSimple(Ids::DEEPSLATE_BRICKS, fn() => Blocks::DEEPSLATE_BRICKS());
|
||||
@ -840,9 +846,11 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->mapSimple(Ids::SPORE_BLOSSOM, fn() => Blocks::SPORE_BLOSSOM());
|
||||
$this->mapSimple(Ids::STONECUTTER, fn() => Blocks::LEGACY_STONECUTTER());
|
||||
$this->mapSimple(Ids::TINTED_GLASS, fn() => Blocks::TINTED_GLASS());
|
||||
$this->mapSimple(Ids::TORCHFLOWER, fn() => Blocks::TORCHFLOWER());
|
||||
$this->mapSimple(Ids::TUFF, fn() => Blocks::TUFF());
|
||||
$this->mapSimple(Ids::UNDYED_SHULKER_BOX, fn() => Blocks::SHULKER_BOX());
|
||||
$this->mapSimple(Ids::WARPED_WART_BLOCK, fn() => Blocks::WARPED_WART_BLOCK());
|
||||
$this->mapSimple(Ids::WARPED_ROOTS, fn() => Blocks::WARPED_ROOTS());
|
||||
$this->mapSimple(Ids::WATERLILY, fn() => Blocks::LILY_PAD());
|
||||
$this->mapSimple(Ids::WEB, fn() => Blocks::COBWEB());
|
||||
$this->mapSimple(Ids::WITHER_ROSE, fn() => Blocks::WITHER_ROSE());
|
||||
@ -855,6 +863,11 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
->setPowered($in->readBool(StateNames::RAIL_DATA_BIT))
|
||||
->setShape($in->readBoundedInt(StateNames::RAIL_DIRECTION, 0, 5));
|
||||
});
|
||||
$this->map(Ids::AMETHYST_CLUSTER, function(Reader $in) : Block{
|
||||
return Blocks::AMETHYST_CLUSTER()
|
||||
->setStage(AmethystCluster::STAGE_CLUSTER)
|
||||
->setFacing($in->readBlockFace());
|
||||
});
|
||||
$this->mapStairs(Ids::ANDESITE_STAIRS, fn() => Blocks::ANDESITE_STAIRS());
|
||||
$this->map(Ids::ANVIL, function(Reader $in) : Block{
|
||||
return Blocks::ANVIL()
|
||||
@ -983,6 +996,18 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
return Blocks::CHAIN()
|
||||
->setAxis($in->readPillarAxis());
|
||||
});
|
||||
$this->map(Ids::CHISELED_BOOKSHELF, function(Reader $in) : Block{
|
||||
$block = Blocks::CHISELED_BOOKSHELF()
|
||||
->setFacing($in->readLegacyHorizontalFacing());
|
||||
|
||||
//we don't use API constant for bounds here as the data bounds might be different to what we support internally
|
||||
$flags = $in->readBoundedInt(StateNames::BOOKS_STORED, 0, (1 << 6) - 1);
|
||||
foreach(ChiseledBookshelfSlot::cases() as $slot){
|
||||
$block->setSlot($slot, ($flags & (1 << $slot->value)) !== 0);
|
||||
}
|
||||
|
||||
return $block;
|
||||
});
|
||||
$this->map(Ids::CHEMISTRY_TABLE, function(Reader $in) : Block{
|
||||
return (match($type = $in->readString(StateNames::CHEMISTRY_TABLE_TYPE)){
|
||||
StringValues::CHEMISTRY_TABLE_TYPE_COMPOUND_CREATOR => Blocks::COMPOUND_CREATOR(),
|
||||
@ -1161,6 +1186,11 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
return Blocks::LANTERN()
|
||||
->setHanging($in->readBool(StateNames::HANGING));
|
||||
});
|
||||
$this->map(Ids::LARGE_AMETHYST_BUD, function(Reader $in) : Block{
|
||||
return Blocks::AMETHYST_CLUSTER()
|
||||
->setStage(AmethystCluster::STAGE_LARGE_BUD)
|
||||
->setFacing($in->readBlockFace());
|
||||
});
|
||||
$this->map(Ids::LAVA, fn(Reader $in) => Helper::decodeStillLiquid(Blocks::LAVA(), $in));
|
||||
$this->map(Ids::LECTERN, function(Reader $in) : Block{
|
||||
return Blocks::LECTERN()
|
||||
@ -1223,6 +1253,11 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
return Blocks::LOOM()
|
||||
->setFacing($in->readLegacyHorizontalFacing());
|
||||
});
|
||||
$this->map(Ids::MEDIUM_AMETHYST_BUD, function(Reader $in) : Block{
|
||||
return Blocks::AMETHYST_CLUSTER()
|
||||
->setStage(AmethystCluster::STAGE_MEDIUM_BUD)
|
||||
->setFacing($in->readBlockFace());
|
||||
});
|
||||
$this->map(Ids::MELON_STEM, fn(Reader $in) => Helper::decodeStem(Blocks::MELON_STEM(), $in));
|
||||
$this->map(Ids::MONSTER_EGG, function(Reader $in) : Block{
|
||||
return match($type = $in->readString(StateNames::MONSTER_EGG_STONE_TYPE)){
|
||||
@ -1263,6 +1298,22 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
->setFacing($in->readCardinalHorizontalFacing())
|
||||
->setCount(min($growth + 1, PinkPetals::MAX_COUNT));
|
||||
});
|
||||
$this->map(Ids::PITCHER_CROP, function(Reader $in) : Block{
|
||||
$growth = $in->readBoundedInt(StateNames::GROWTH, 0, 7);
|
||||
$top = $in->readBool(StateNames::UPPER_BLOCK_BIT);
|
||||
if($growth <= PitcherCrop::MAX_AGE){
|
||||
//top pitcher crop with age 0-2 is an invalid state
|
||||
//only the bottom half should exist in this case
|
||||
return $top ? Blocks::AIR() : Blocks::PITCHER_CROP()->setAge($growth);
|
||||
}
|
||||
return Blocks::DOUBLE_PITCHER_CROP()
|
||||
->setAge(min($growth - PitcherCrop::MAX_AGE - 1, DoublePitcherCrop::MAX_AGE))
|
||||
->setTop($top);
|
||||
});
|
||||
$this->map(Ids::PITCHER_PLANT, function(Reader $in) : Block{
|
||||
return Blocks::PITCHER_PLANT()
|
||||
->setTop($in->readBool(StateNames::UPPER_BLOCK_BIT));
|
||||
});
|
||||
$this->mapStairs(Ids::POLISHED_ANDESITE_STAIRS, fn() => Blocks::POLISHED_ANDESITE_STAIRS());
|
||||
$this->map(Ids::POLISHED_BASALT, function(Reader $in) : Block{
|
||||
return Blocks::POLISHED_BASALT()
|
||||
@ -1437,6 +1488,11 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
->setFacing($in->readCardinalHorizontalFacing())
|
||||
->setLit(false);
|
||||
});
|
||||
$this->map(Ids::SMALL_AMETHYST_BUD, function(Reader $in) : Block{
|
||||
return Blocks::AMETHYST_CLUSTER()
|
||||
->setStage(AmethystCluster::STAGE_SMALL_BUD)
|
||||
->setFacing($in->readBlockFace());
|
||||
});
|
||||
$this->map(Ids::SMALL_DRIPLEAF_BLOCK, function(Reader $in) : Block{
|
||||
return Blocks::SMALL_DRIPLEAF()
|
||||
->setFacing($in->readCardinalHorizontalFacing())
|
||||
@ -1528,6 +1584,11 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
return Blocks::TORCH()
|
||||
->setFacing($in->readTorchFacing());
|
||||
});
|
||||
$this->map(Ids::TORCHFLOWER_CROP, function(Reader $in) : Block{
|
||||
return Blocks::TORCHFLOWER_CROP()
|
||||
//this property can have values 0-7, but only 0-1 are valid
|
||||
->setReady($in->readBoundedInt(StateNames::GROWTH, 0, 7) !== 0);
|
||||
});
|
||||
$this->map(Ids::TRAPPED_CHEST, function(Reader $in) : Block{
|
||||
return Blocks::TRAPPED_CHEST()
|
||||
->setFacing($in->readHorizontalFacing());
|
||||
|
@ -90,6 +90,20 @@ final class BlockStateWriter{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @return $this */
|
||||
public function writeBlockFace(int $value) : self{
|
||||
$this->writeString(BlockStateNames::MC_BLOCK_FACE, match($value){
|
||||
Facing::DOWN => StringValues::MC_BLOCK_FACE_DOWN,
|
||||
Facing::UP => StringValues::MC_BLOCK_FACE_UP,
|
||||
Facing::NORTH => StringValues::MC_BLOCK_FACE_NORTH,
|
||||
Facing::SOUTH => StringValues::MC_BLOCK_FACE_SOUTH,
|
||||
Facing::WEST => StringValues::MC_BLOCK_FACE_WEST,
|
||||
Facing::EAST => StringValues::MC_BLOCK_FACE_EAST,
|
||||
default => throw new BlockStateSerializeException("Invalid Facing $value")
|
||||
});
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $faces
|
||||
* @phpstan-param array<int, int> $faces
|
||||
|
@ -147,6 +147,7 @@ final class ItemSerializerDeserializerRegistrar{
|
||||
$this->map1to1Block(Ids::JUNGLE_DOOR, Blocks::JUNGLE_DOOR());
|
||||
$this->map1to1Block(Ids::MANGROVE_DOOR, Blocks::MANGROVE_DOOR());
|
||||
$this->map1to1Block(Ids::NETHER_WART, Blocks::NETHER_WART());
|
||||
$this->map1to1Block(Ids::PITCHER_POD, Blocks::PITCHER_CROP());
|
||||
$this->map1to1Block(Ids::REPEATER, Blocks::REDSTONE_REPEATER());
|
||||
$this->map1to1Block(Ids::SPRUCE_DOOR, Blocks::SPRUCE_DOOR());
|
||||
$this->map1to1Block(Ids::SUGAR_CANE, Blocks::SUGARCANE());
|
||||
@ -359,6 +360,7 @@ final class ItemSerializerDeserializerRegistrar{
|
||||
$this->map1to1Item(Ids::STRING, Items::STRING());
|
||||
$this->map1to1Item(Ids::SUGAR, Items::SUGAR());
|
||||
$this->map1to1Item(Ids::SWEET_BERRIES, Items::SWEET_BERRIES());
|
||||
$this->map1to1Item(Ids::TORCHFLOWER_SEEDS, Items::TORCHFLOWER_SEEDS());
|
||||
$this->map1to1Item(Ids::TOTEM_OF_UNDYING, Items::TOTEM());
|
||||
$this->map1to1Item(Ids::TROPICAL_FISH, Items::CLOWNFISH());
|
||||
$this->map1to1Item(Ids::TURTLE_HELMET, Items::TURTLE_HELMET());
|
||||
|
@ -71,6 +71,8 @@ interface RuntimeDataDescriber{
|
||||
/**
|
||||
* @param BrewingStandSlot[] $slots
|
||||
* @phpstan-param array<int, BrewingStandSlot> $slots
|
||||
*
|
||||
* @deprecated Use {@link enumSet()} instead.
|
||||
*/
|
||||
public function brewingStandSlots(array &$slots) : void;
|
||||
|
||||
@ -83,4 +85,14 @@ interface RuntimeDataDescriber{
|
||||
* @phpstan-param T $case
|
||||
*/
|
||||
public function enum(\UnitEnum &$case) : void;
|
||||
|
||||
/**
|
||||
* @param \UnitEnum[] &$set
|
||||
* @param \UnitEnum[] $allCases
|
||||
*
|
||||
* @phpstan-template T of \UnitEnum
|
||||
* @phpstan-param array<int, T> &$set
|
||||
* @phpstan-param array<int, T> $allCases
|
||||
*/
|
||||
public function enumSet(array &$set, array $allCases) : void;
|
||||
}
|
||||
|
@ -179,16 +179,11 @@ final class RuntimeDataReader implements RuntimeDataDescriber{
|
||||
/**
|
||||
* @param BrewingStandSlot[] $slots
|
||||
* @phpstan-param array<int, BrewingStandSlot> $slots
|
||||
*
|
||||
* @deprecated Use {@link enumSet()} instead.
|
||||
*/
|
||||
public function brewingStandSlots(array &$slots) : void{
|
||||
$result = [];
|
||||
foreach(BrewingStandSlot::cases() as $member){
|
||||
if($this->readBool()){
|
||||
$result[spl_object_id($member)] = $member;
|
||||
}
|
||||
}
|
||||
|
||||
$slots = $result;
|
||||
$this->enumSet($slots, BrewingStandSlot::cases());
|
||||
}
|
||||
|
||||
public function railShape(int &$railShape) : void{
|
||||
@ -220,5 +215,15 @@ final class RuntimeDataReader implements RuntimeDataDescriber{
|
||||
$case = $result;
|
||||
}
|
||||
|
||||
public function enumSet(array &$set, array $allCases) : void{
|
||||
$result = [];
|
||||
foreach($allCases as $case){
|
||||
if($this->readBool()){
|
||||
$result[spl_object_id($case)] = $case;
|
||||
}
|
||||
}
|
||||
$set = $result;
|
||||
}
|
||||
|
||||
public function getOffset() : int{ return $this->offset; }
|
||||
}
|
||||
|
@ -98,4 +98,8 @@ final class RuntimeDataSizeCalculator implements RuntimeDataDescriber{
|
||||
$metadata = RuntimeEnumMetadata::from($case);
|
||||
$this->addBits($metadata->bits);
|
||||
}
|
||||
|
||||
public function enumSet(array &$set, array $allCases) : void{
|
||||
$this->addBits(count($allCases));
|
||||
}
|
||||
}
|
||||
|
@ -157,11 +157,11 @@ final class RuntimeDataWriter implements RuntimeDataDescriber{
|
||||
/**
|
||||
* @param BrewingStandSlot[] $slots
|
||||
* @phpstan-param array<int, BrewingStandSlot> $slots
|
||||
*
|
||||
* @deprecated Use {@link enumSet()} instead.
|
||||
*/
|
||||
public function brewingStandSlots(array &$slots) : void{
|
||||
foreach(BrewingStandSlot::cases() as $member){
|
||||
$this->writeBool(isset($slots[spl_object_id($member)]));
|
||||
}
|
||||
$this->enumSet($slots, BrewingStandSlot::cases());
|
||||
}
|
||||
|
||||
public function railShape(int &$railShape) : void{
|
||||
@ -177,6 +177,12 @@ final class RuntimeDataWriter implements RuntimeDataDescriber{
|
||||
$this->writeInt($metadata->bits, $metadata->enumToInt($case));
|
||||
}
|
||||
|
||||
public function enumSet(array &$set, array $allCases) : void{
|
||||
foreach($allCases as $case){
|
||||
$this->writeBool(isset($set[spl_object_id($case)]));
|
||||
}
|
||||
}
|
||||
|
||||
public function getValue() : int{ return $this->value; }
|
||||
|
||||
public function getOffset() : int{ return $this->offset; }
|
||||
|
@ -1686,7 +1686,7 @@ abstract class Entity{
|
||||
*/
|
||||
public function broadcastSound(Sound $sound, ?array $targets = null) : void{
|
||||
if(!$this->silent){
|
||||
NetworkBroadcastUtils::broadcastPackets($targets ?? $this->getViewers(), $sound->encode($this->location));
|
||||
$this->getWorld()->addSound($this->location->asVector3(), $sound, $targets ?? $this->getViewers());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,8 +304,9 @@ final class ItemTypeIds{
|
||||
public const GLOW_BERRIES = 20265;
|
||||
public const CHERRY_SIGN = 20266;
|
||||
public const ENCHANTED_BOOK = 20267;
|
||||
public const TORCHFLOWER_SEEDS = 20268;
|
||||
|
||||
public const FIRST_UNUSED_ITEM_ID = 20268;
|
||||
public const FIRST_UNUSED_ITEM_ID = 20269;
|
||||
|
||||
private static int $nextDynamicId = self::FIRST_UNUSED_ITEM_ID;
|
||||
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\item;
|
||||
|
||||
use pocketmine\block\AmethystCluster;
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\Light;
|
||||
use pocketmine\block\utils\CopperOxidation;
|
||||
@ -134,6 +135,7 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->registerBlock("all_sided_mushroom_stem", fn() => Blocks::ALL_SIDED_MUSHROOM_STEM());
|
||||
$result->registerBlock("allium", fn() => Blocks::ALLIUM());
|
||||
$result->registerBlock("amethyst_block", fn() => Blocks::AMETHYST());
|
||||
$result->registerBlock("amethyst_cluster", fn() => Blocks::AMETHYST_CLUSTER());
|
||||
$result->registerBlock("ancient_debris", fn() => Blocks::ANCIENT_DEBRIS());
|
||||
$result->registerBlock("andesite", fn() => Blocks::ANDESITE());
|
||||
$result->registerBlock("andesite_slab", fn() => Blocks::ANDESITE_SLAB());
|
||||
@ -196,6 +198,7 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->registerBlock("bricks_block", fn() => Blocks::BRICKS());
|
||||
$result->registerBlock("brown_mushroom", fn() => Blocks::BROWN_MUSHROOM());
|
||||
$result->registerBlock("brown_mushroom_block", fn() => Blocks::BROWN_MUSHROOM_BLOCK());
|
||||
$result->registerBlock("budding_amethyst", fn() => Blocks::BUDDING_AMETHYST());
|
||||
$result->registerBlock("burning_furnace", fn() => Blocks::FURNACE());
|
||||
$result->registerBlock("bush", fn() => Blocks::DEAD_BUSH());
|
||||
$result->registerBlock("cactus", fn() => Blocks::CACTUS());
|
||||
@ -227,6 +230,7 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->registerBlock("chemistry_table", fn() => Blocks::COMPOUND_CREATOR());
|
||||
$result->registerBlock("chest", fn() => Blocks::CHEST());
|
||||
$result->registerBlock("chipped_anvil", fn() => Blocks::ANVIL()->setDamage(1));
|
||||
$result->registerBlock("chiseled_bookshelf", fn() => Blocks::CHISELED_BOOKSHELF());
|
||||
$result->registerBlock("chiseled_deepslate", fn() => Blocks::CHISELED_DEEPSLATE());
|
||||
$result->registerBlock("chiseled_nether_bricks", fn() => Blocks::CHISELED_NETHER_BRICKS());
|
||||
$result->registerBlock("chiseled_polished_blackstone", fn() => Blocks::CHISELED_POLISHED_BLACKSTONE());
|
||||
@ -287,6 +291,7 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->registerBlock("crimson_hyphae", fn() => Blocks::CRIMSON_HYPHAE()->setStripped(false));
|
||||
$result->registerBlock("crimson_planks", fn() => Blocks::CRIMSON_PLANKS());
|
||||
$result->registerBlock("crimson_pressure_plate", fn() => Blocks::CRIMSON_PRESSURE_PLATE());
|
||||
$result->registerBlock("crimson_roots", fn() => Blocks::CRIMSON_ROOTS());
|
||||
$result->registerBlock("crimson_sign", fn() => Blocks::CRIMSON_SIGN());
|
||||
$result->registerBlock("crimson_slab", fn() => Blocks::CRIMSON_SLAB());
|
||||
$result->registerBlock("crimson_stairs", fn() => Blocks::CRIMSON_STAIRS());
|
||||
@ -743,6 +748,7 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->registerBlock("lapis_lazuli_block", fn() => Blocks::LAPIS_LAZULI());
|
||||
$result->registerBlock("lapis_lazuli_ore", fn() => Blocks::LAPIS_LAZULI_ORE());
|
||||
$result->registerBlock("lapis_ore", fn() => Blocks::LAPIS_LAZULI_ORE());
|
||||
$result->registerBlock("large_amethyst_bud", fn() => Blocks::AMETHYST_CLUSTER()->setStage(AmethystCluster::STAGE_LARGE_BUD));
|
||||
$result->registerBlock("large_fern", fn() => Blocks::LARGE_FERN());
|
||||
$result->registerBlock("lava", fn() => Blocks::LAVA());
|
||||
$result->registerBlock("leave", fn() => Blocks::OAK_LEAVES());
|
||||
@ -785,6 +791,7 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->registerBlock("mangrove_trapdoor", fn() => Blocks::MANGROVE_TRAPDOOR());
|
||||
$result->registerBlock("mangrove_wood", fn() => Blocks::MANGROVE_WOOD()->setStripped(false));
|
||||
$result->registerBlock("material_reducer", fn() => Blocks::MATERIAL_REDUCER());
|
||||
$result->registerBlock("medium_amethyst_bud", fn() => Blocks::AMETHYST_CLUSTER()->setStage(AmethystCluster::STAGE_MEDIUM_BUD));
|
||||
$result->registerBlock("melon_block", fn() => Blocks::MELON());
|
||||
$result->registerBlock("melon_stem", fn() => Blocks::MELON_STEM());
|
||||
$result->registerBlock("mob_head", fn() => Blocks::MOB_HEAD());
|
||||
@ -975,6 +982,7 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->registerBlock("slabs", fn() => Blocks::SMOOTH_STONE_SLAB());
|
||||
$result->registerBlock("slime", fn() => Blocks::SLIME());
|
||||
$result->registerBlock("slime_block", fn() => Blocks::SLIME());
|
||||
$result->registerBlock("small_amethyst_bud", fn() => Blocks::AMETHYST_CLUSTER()->setStage(AmethystCluster::STAGE_SMALL_BUD));
|
||||
$result->registerBlock("small_dripleaf", fn() => Blocks::SMALL_DRIPLEAF());
|
||||
$result->registerBlock("smoker", fn() => Blocks::SMOKER());
|
||||
$result->registerBlock("smooth_basalt", fn() => Blocks::SMOOTH_BASALT());
|
||||
@ -1074,6 +1082,7 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->registerBlock("tinted_glass", fn() => Blocks::TINTED_GLASS());
|
||||
$result->registerBlock("tnt", fn() => Blocks::TNT());
|
||||
$result->registerBlock("torch", fn() => Blocks::TORCH());
|
||||
$result->registerBlock("torchflower", fn() => Blocks::TORCHFLOWER());
|
||||
$result->registerBlock("trapdoor", fn() => Blocks::OAK_TRAPDOOR());
|
||||
$result->registerBlock("trapped_chest", fn() => Blocks::TRAPPED_CHEST());
|
||||
$result->registerBlock("trip_wire", fn() => Blocks::TRIPWIRE());
|
||||
@ -1104,6 +1113,7 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->registerBlock("warped_hyphae", fn() => Blocks::WARPED_HYPHAE()->setStripped(false));
|
||||
$result->registerBlock("warped_planks", fn() => Blocks::WARPED_PLANKS());
|
||||
$result->registerBlock("warped_pressure_plate", fn() => Blocks::WARPED_PRESSURE_PLATE());
|
||||
$result->registerBlock("warped_roots", fn() => Blocks::WARPED_ROOTS());
|
||||
$result->registerBlock("warped_sign", fn() => Blocks::WARPED_SIGN());
|
||||
$result->registerBlock("warped_slab", fn() => Blocks::WARPED_SLAB());
|
||||
$result->registerBlock("warped_stairs", fn() => Blocks::WARPED_STAIRS());
|
||||
@ -1154,6 +1164,13 @@ final class StringToItemParser extends StringToTParser{
|
||||
|
||||
$result->register($prefix("suspicious_stew"), fn() => Items::SUSPICIOUS_STEW()->setType($suspiciousStewType));
|
||||
}
|
||||
|
||||
foreach(PotionType::cases() as $potionType){
|
||||
$prefix = fn(string $name) => strtolower($potionType->name) . "_" . $name;
|
||||
|
||||
$result->register($prefix("potion"), fn() => Items::POTION()->setType($potionType));
|
||||
$result->register($prefix("splash_potion"), fn() => Items::SPLASH_POTION()->setType($potionType));
|
||||
}
|
||||
}
|
||||
|
||||
private static function registerItems(self $result) : void{
|
||||
@ -1165,8 +1182,6 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->register("apple_enchanted", fn() => Items::ENCHANTED_GOLDEN_APPLE());
|
||||
$result->register("appleenchanted", fn() => Items::ENCHANTED_GOLDEN_APPLE());
|
||||
$result->register("arrow", fn() => Items::ARROW());
|
||||
$result->register("awkward_potion", fn() => Items::POTION()->setType(PotionType::AWKWARD));
|
||||
$result->register("awkward_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::AWKWARD));
|
||||
$result->register("baked_potato", fn() => Items::BAKED_POTATO());
|
||||
$result->register("baked_potatoes", fn() => Items::BAKED_POTATO());
|
||||
$result->register("beef", fn() => Items::RAW_BEEF());
|
||||
@ -1287,8 +1302,6 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->register("feather", fn() => Items::FEATHER());
|
||||
$result->register("fermented_spider_eye", fn() => Items::FERMENTED_SPIDER_EYE());
|
||||
$result->register("fire_charge", fn() => Items::FIRE_CHARGE());
|
||||
$result->register("fire_resistance_potion", fn() => Items::POTION()->setType(PotionType::FIRE_RESISTANCE));
|
||||
$result->register("fire_resistance_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::FIRE_RESISTANCE));
|
||||
$result->register("fish", fn() => Items::RAW_FISH());
|
||||
$result->register("fishing_rod", fn() => Items::FISHING_ROD());
|
||||
$result->register("flint", fn() => Items::FLINT());
|
||||
@ -1324,16 +1337,10 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->register("golden_shovel", fn() => Items::GOLDEN_SHOVEL());
|
||||
$result->register("golden_sword", fn() => Items::GOLDEN_SWORD());
|
||||
$result->register("gunpowder", fn() => Items::GUNPOWDER());
|
||||
$result->register("harming_potion", fn() => Items::POTION()->setType(PotionType::HARMING));
|
||||
$result->register("harming_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::HARMING));
|
||||
$result->register("healing_potion", fn() => Items::POTION()->setType(PotionType::HEALING));
|
||||
$result->register("healing_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::HEALING));
|
||||
$result->register("heart_of_the_sea", fn() => Items::HEART_OF_THE_SEA());
|
||||
$result->register("honey_bottle", fn() => Items::HONEY_BOTTLE());
|
||||
$result->register("honeycomb", fn() => Items::HONEYCOMB());
|
||||
$result->register("ink_sac", fn() => Items::INK_SAC());
|
||||
$result->register("invisibility_potion", fn() => Items::POTION()->setType(PotionType::INVISIBILITY));
|
||||
$result->register("invisibility_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::INVISIBILITY));
|
||||
$result->register("iron_axe", fn() => Items::IRON_AXE());
|
||||
$result->register("iron_boots", fn() => Items::IRON_BOOTS());
|
||||
$result->register("iron_chestplate", fn() => Items::IRON_CHESTPLATE());
|
||||
@ -1348,8 +1355,6 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->register("jungle_boat", fn() => Items::JUNGLE_BOAT());
|
||||
$result->register("lapis_lazuli", fn() => Items::LAPIS_LAZULI());
|
||||
$result->register("lava_bucket", fn() => Items::LAVA_BUCKET());
|
||||
$result->register("leaping_potion", fn() => Items::POTION()->setType(PotionType::LEAPING));
|
||||
$result->register("leaping_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::LEAPING));
|
||||
$result->register("leather", fn() => Items::LEATHER());
|
||||
$result->register("leather_boots", fn() => Items::LEATHER_BOOTS());
|
||||
$result->register("leather_cap", fn() => Items::LEATHER_CAP());
|
||||
@ -1358,42 +1363,12 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->register("leather_leggings", fn() => Items::LEATHER_PANTS());
|
||||
$result->register("leather_pants", fn() => Items::LEATHER_PANTS());
|
||||
$result->register("leather_tunic", fn() => Items::LEATHER_TUNIC());
|
||||
$result->register("long_fire_resistance_potion", fn() => Items::POTION()->setType(PotionType::LONG_FIRE_RESISTANCE));
|
||||
$result->register("long_fire_resistance_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::LONG_FIRE_RESISTANCE));
|
||||
$result->register("long_invisibility_potion", fn() => Items::POTION()->setType(PotionType::LONG_INVISIBILITY));
|
||||
$result->register("long_invisibility_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::LONG_INVISIBILITY));
|
||||
$result->register("long_leaping_potion", fn() => Items::POTION()->setType(PotionType::LONG_LEAPING));
|
||||
$result->register("long_leaping_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::LONG_LEAPING));
|
||||
$result->register("long_mundane_potion", fn() => Items::POTION()->setType(PotionType::LONG_MUNDANE));
|
||||
$result->register("long_mundane_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::LONG_MUNDANE));
|
||||
$result->register("long_night_vision_potion", fn() => Items::POTION()->setType(PotionType::LONG_NIGHT_VISION));
|
||||
$result->register("long_night_vision_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::LONG_NIGHT_VISION));
|
||||
$result->register("long_poison_potion", fn() => Items::POTION()->setType(PotionType::LONG_POISON));
|
||||
$result->register("long_poison_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::LONG_POISON));
|
||||
$result->register("long_regeneration_potion", fn() => Items::POTION()->setType(PotionType::LONG_REGENERATION));
|
||||
$result->register("long_regeneration_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::LONG_REGENERATION));
|
||||
$result->register("long_slow_falling_potion", fn() => Items::POTION()->setType(PotionType::LONG_SLOW_FALLING));
|
||||
$result->register("long_slow_falling_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::LONG_SLOW_FALLING));
|
||||
$result->register("long_slowness_potion", fn() => Items::POTION()->setType(PotionType::LONG_SLOWNESS));
|
||||
$result->register("long_slowness_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::LONG_SLOWNESS));
|
||||
$result->register("long_strength_potion", fn() => Items::POTION()->setType(PotionType::LONG_STRENGTH));
|
||||
$result->register("long_strength_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::LONG_STRENGTH));
|
||||
$result->register("long_swiftness_potion", fn() => Items::POTION()->setType(PotionType::LONG_SWIFTNESS));
|
||||
$result->register("long_swiftness_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::LONG_SWIFTNESS));
|
||||
$result->register("long_turtle_master_potion", fn() => Items::POTION()->setType(PotionType::LONG_TURTLE_MASTER));
|
||||
$result->register("long_turtle_master_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::LONG_TURTLE_MASTER));
|
||||
$result->register("long_water_breathing_potion", fn() => Items::POTION()->setType(PotionType::LONG_WATER_BREATHING));
|
||||
$result->register("long_water_breathing_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::LONG_WATER_BREATHING));
|
||||
$result->register("long_weakness_potion", fn() => Items::POTION()->setType(PotionType::LONG_WEAKNESS));
|
||||
$result->register("long_weakness_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::LONG_WEAKNESS));
|
||||
$result->register("magma_cream", fn() => Items::MAGMA_CREAM());
|
||||
$result->register("melon", fn() => Items::MELON());
|
||||
$result->register("melon_seeds", fn() => Items::MELON_SEEDS());
|
||||
$result->register("melon_slice", fn() => Items::MELON());
|
||||
$result->register("milk_bucket", fn() => Items::MILK_BUCKET());
|
||||
$result->register("minecart", fn() => Items::MINECART());
|
||||
$result->register("mundane_potion", fn() => Items::POTION()->setType(PotionType::MUNDANE));
|
||||
$result->register("mundane_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::MUNDANE));
|
||||
$result->register("mushroom_stew", fn() => Items::MUSHROOM_STEW());
|
||||
$result->register("mutton", fn() => Items::RAW_MUTTON());
|
||||
$result->register("mutton_cooked", fn() => Items::COOKED_MUTTON());
|
||||
@ -1417,14 +1392,10 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->register("netherite_shovel", fn() => Items::NETHERITE_SHOVEL());
|
||||
$result->register("netherite_sword", fn() => Items::NETHERITE_SWORD());
|
||||
$result->register("netherstar", fn() => Items::NETHER_STAR());
|
||||
$result->register("night_vision_potion", fn() => Items::POTION()->setType(PotionType::NIGHT_VISION));
|
||||
$result->register("night_vision_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::NIGHT_VISION));
|
||||
$result->register("oak_boat", fn() => Items::OAK_BOAT());
|
||||
$result->register("painting", fn() => Items::PAINTING());
|
||||
$result->register("paper", fn() => Items::PAPER());
|
||||
$result->register("phantom_membrane", fn() => Items::PHANTOM_MEMBRANE());
|
||||
$result->register("poison_potion", fn() => Items::POTION()->setType(PotionType::POISON));
|
||||
$result->register("poison_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::POISON));
|
||||
$result->register("poisonous_potato", fn() => Items::POISONOUS_POTATO());
|
||||
$result->register("popped_chorus_fruit", fn() => Items::POPPED_CHORUS_FRUIT());
|
||||
$result->register("porkchop", fn() => Items::RAW_PORKCHOP());
|
||||
@ -1469,8 +1440,6 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->register("record_ward", fn() => Items::RECORD_WARD());
|
||||
$result->register("redstone", fn() => Items::REDSTONE_DUST());
|
||||
$result->register("redstone_dust", fn() => Items::REDSTONE_DUST());
|
||||
$result->register("regeneration_potion", fn() => Items::POTION()->setType(PotionType::REGENERATION));
|
||||
$result->register("regeneration_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::REGENERATION));
|
||||
$result->register("rotten_flesh", fn() => Items::ROTTEN_FLESH());
|
||||
$result->register("salmon", fn() => Items::RAW_SALMON());
|
||||
$result->register("scute", fn() => Items::SCUTE());
|
||||
@ -1479,10 +1448,6 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->register("shulker_shell", fn() => Items::SHULKER_SHELL());
|
||||
$result->register("slime_ball", fn() => Items::SLIMEBALL());
|
||||
$result->register("slimeball", fn() => Items::SLIMEBALL());
|
||||
$result->register("slow_falling_potion", fn() => Items::POTION()->setType(PotionType::SLOW_FALLING));
|
||||
$result->register("slow_falling_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::SLOW_FALLING));
|
||||
$result->register("slowness_potion", fn() => Items::POTION()->setType(PotionType::SLOWNESS));
|
||||
$result->register("slowness_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::SLOWNESS));
|
||||
$result->register("snowball", fn() => Items::SNOWBALL());
|
||||
$result->register("speckled_melon", fn() => Items::GLISTERING_MELON());
|
||||
$result->register("spider_eye", fn() => Items::SPIDER_EYE());
|
||||
@ -1498,52 +1463,19 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->register("stone_pickaxe", fn() => Items::STONE_PICKAXE());
|
||||
$result->register("stone_shovel", fn() => Items::STONE_SHOVEL());
|
||||
$result->register("stone_sword", fn() => Items::STONE_SWORD());
|
||||
$result->register("strength_potion", fn() => Items::POTION()->setType(PotionType::STRENGTH));
|
||||
$result->register("strength_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::STRENGTH));
|
||||
$result->register("string", fn() => Items::STRING());
|
||||
$result->register("strong_harming_potion", fn() => Items::POTION()->setType(PotionType::STRONG_HARMING));
|
||||
$result->register("strong_harming_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::STRONG_HARMING));
|
||||
$result->register("strong_healing_potion", fn() => Items::POTION()->setType(PotionType::STRONG_HEALING));
|
||||
$result->register("strong_healing_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::STRONG_HEALING));
|
||||
$result->register("strong_leaping_potion", fn() => Items::POTION()->setType(PotionType::STRONG_LEAPING));
|
||||
$result->register("strong_leaping_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::STRONG_LEAPING));
|
||||
$result->register("strong_poison_potion", fn() => Items::POTION()->setType(PotionType::STRONG_POISON));
|
||||
$result->register("strong_poison_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::STRONG_POISON));
|
||||
$result->register("strong_regeneration_potion", fn() => Items::POTION()->setType(PotionType::STRONG_REGENERATION));
|
||||
$result->register("strong_regeneration_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::STRONG_REGENERATION));
|
||||
$result->register("strong_slowness_potion", fn() => Items::POTION()->setType(PotionType::STRONG_SLOWNESS));
|
||||
$result->register("strong_slowness_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::STRONG_SLOWNESS));
|
||||
$result->register("strong_strength_potion", fn() => Items::POTION()->setType(PotionType::STRONG_STRENGTH));
|
||||
$result->register("strong_strength_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::STRONG_STRENGTH));
|
||||
$result->register("strong_swiftness_potion", fn() => Items::POTION()->setType(PotionType::STRONG_SWIFTNESS));
|
||||
$result->register("strong_swiftness_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::STRONG_SWIFTNESS));
|
||||
$result->register("strong_turtle_master_potion", fn() => Items::POTION()->setType(PotionType::STRONG_TURTLE_MASTER));
|
||||
$result->register("strong_turtle_master_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::STRONG_TURTLE_MASTER));
|
||||
$result->register("sugar", fn() => Items::SUGAR());
|
||||
$result->register("suspicious_stew", fn() => Items::SUSPICIOUS_STEW());
|
||||
$result->register("sweet_berries", fn() => Items::SWEET_BERRIES());
|
||||
$result->register("swiftness_potion", fn() => Items::POTION()->setType(PotionType::SWIFTNESS));
|
||||
$result->register("swiftness_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::SWIFTNESS));
|
||||
$result->register("thick_potion", fn() => Items::POTION()->setType(PotionType::THICK));
|
||||
$result->register("thick_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::THICK));
|
||||
$result->register("tonic", fn() => Items::MEDICINE()->setType(MedicineType::TONIC));
|
||||
$result->register("torchflower_seeds", fn() => Items::TORCHFLOWER_SEEDS());
|
||||
$result->register("totem", fn() => Items::TOTEM());
|
||||
$result->register("turtle_helmet", fn() => Items::TURTLE_HELMET());
|
||||
$result->register("turtle_master_potion", fn() => Items::POTION()->setType(PotionType::TURTLE_MASTER));
|
||||
$result->register("turtle_master_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::TURTLE_MASTER));
|
||||
$result->register("turtle_shell_piece", fn() => Items::SCUTE());
|
||||
$result->register("villager_spawn_egg", fn() => Items::VILLAGER_SPAWN_EGG());
|
||||
$result->register("water_breathing_potion", fn() => Items::POTION()->setType(PotionType::WATER_BREATHING));
|
||||
$result->register("water_breathing_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::WATER_BREATHING));
|
||||
$result->register("water_bucket", fn() => Items::WATER_BUCKET());
|
||||
$result->register("water_potion", fn() => Items::POTION()->setType(PotionType::WATER));
|
||||
$result->register("water_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::WATER));
|
||||
$result->register("weakness_potion", fn() => Items::POTION()->setType(PotionType::WEAKNESS));
|
||||
$result->register("weakness_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::WEAKNESS));
|
||||
$result->register("wheat", fn() => Items::WHEAT());
|
||||
$result->register("wheat_seeds", fn() => Items::WHEAT_SEEDS());
|
||||
$result->register("wither_potion", fn() => Items::POTION()->setType(PotionType::WITHER));
|
||||
$result->register("wither_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::WITHER));
|
||||
$result->register("wooden_axe", fn() => Items::WOODEN_AXE());
|
||||
$result->register("wooden_hoe", fn() => Items::WOODEN_HOE());
|
||||
$result->register("wooden_pickaxe", fn() => Items::WOODEN_PICKAXE());
|
||||
|
34
src/item/TorchflowerSeeds.php
Normal file
34
src/item/TorchflowerSeeds.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?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\item;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\VanillaBlocks;
|
||||
|
||||
final class TorchflowerSeeds extends Item{
|
||||
|
||||
public function getBlock(?int $clickedFace = null) : Block{
|
||||
return VanillaBlocks::TORCHFLOWER_CROP();
|
||||
}
|
||||
}
|
@ -296,6 +296,7 @@ use function strtolower;
|
||||
* @method static Item SUGAR()
|
||||
* @method static SuspiciousStew SUSPICIOUS_STEW()
|
||||
* @method static SweetBerries SWEET_BERRIES()
|
||||
* @method static TorchflowerSeeds TORCHFLOWER_SEEDS()
|
||||
* @method static Totem TOTEM()
|
||||
* @method static TurtleHelmet TURTLE_HELMET()
|
||||
* @method static SpawnEgg VILLAGER_SPAWN_EGG()
|
||||
@ -538,6 +539,7 @@ final class VanillaItems{
|
||||
self::register("sugar", new Item(new IID(Ids::SUGAR), "Sugar"));
|
||||
self::register("suspicious_stew", new SuspiciousStew(new IID(Ids::SUSPICIOUS_STEW), "Suspicious Stew"));
|
||||
self::register("sweet_berries", new SweetBerries(new IID(Ids::SWEET_BERRIES), "Sweet Berries"));
|
||||
self::register("torchflower_seeds", new TorchflowerSeeds(new IID(Ids::TORCHFLOWER_SEEDS), "Torchflower Seeds"));
|
||||
self::register("totem", new Totem(new IID(Ids::TOTEM), "Totem of Undying"));
|
||||
self::register("warped_sign", new ItemBlockWallOrFloor(new IID(Ids::WARPED_SIGN), Blocks::WARPED_SIGN(), Blocks::WARPED_WALL_SIGN()));
|
||||
self::register("water_bucket", new LiquidBucket(new IID(Ids::WATER_BUCKET), "Water Bucket", Blocks::WATER()));
|
||||
|
@ -83,6 +83,9 @@ class LoginPacketHandler extends PacketHandler{
|
||||
throw new PacketHandlingException("Invalid login UUID");
|
||||
}
|
||||
$uuid = Uuid::fromString($extraData->identity);
|
||||
$arrClientData = (array) $clientData;
|
||||
$arrClientData["TitleID"] = $extraData->titleId;
|
||||
|
||||
if($extraData->XUID !== ""){
|
||||
$playerInfo = new XboxLivePlayerInfo(
|
||||
$extraData->XUID,
|
||||
@ -90,7 +93,7 @@ class LoginPacketHandler extends PacketHandler{
|
||||
$uuid,
|
||||
$skin,
|
||||
$clientData->LanguageCode,
|
||||
(array) $clientData
|
||||
$arrClientData
|
||||
);
|
||||
}else{
|
||||
$playerInfo = new PlayerInfo(
|
||||
@ -98,7 +101,7 @@ class LoginPacketHandler extends PacketHandler{
|
||||
$uuid,
|
||||
$skin,
|
||||
$clientData->LanguageCode,
|
||||
(array) $clientData
|
||||
$arrClientData
|
||||
);
|
||||
}
|
||||
($this->playerInfoConsumer)($playerInfo);
|
||||
|
@ -2873,7 +2873,15 @@ class World implements ChunkManager{
|
||||
}elseif($this->getTile($tilePosition) !== null){
|
||||
$logger->error("Cannot add tile at x=$tilePosition->x,y=$tilePosition->y,z=$tilePosition->z: Another tile is already at that position");
|
||||
}else{
|
||||
$this->addTile($tile);
|
||||
$block = $this->getBlockAt($tilePosition->getFloorX(), $tilePosition->getFloorY(), $tilePosition->getFloorZ());
|
||||
$expectedClass = $block->getIdInfo()->getTileClass();
|
||||
if($expectedClass === null){
|
||||
$logger->error("Cannot add tile at x=$tilePosition->x,y=$tilePosition->y,z=$tilePosition->z: Block at that position (" . $block->getName() . ") does not expect a tile");
|
||||
}elseif(!($tile instanceof $expectedClass)){
|
||||
$logger->error("Cannot add tile at x=$tilePosition->x,y=$tilePosition->y,z=$tilePosition->z: Tile is of wrong type (expected $expectedClass but have " . get_class($tile) . ")");
|
||||
}else{
|
||||
$this->addTile($tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,8 +28,8 @@ final class LightPropagationContext{
|
||||
/** @phpstan-var \SplQueue<array{int, int, int}> */
|
||||
public \SplQueue $spreadQueue;
|
||||
/**
|
||||
* @var true[]
|
||||
* @phpstan-var array<int, true>
|
||||
* @var int[]|true[]
|
||||
* @phpstan-var array<int, int|true>
|
||||
*/
|
||||
public array $spreadVisited = [];
|
||||
|
||||
|
@ -137,6 +137,7 @@ abstract class LightUpdate{
|
||||
while(!$context->spreadQueue->isEmpty()){
|
||||
$touched++;
|
||||
[$x, $y, $z] = $context->spreadQueue->dequeue();
|
||||
$from = $context->spreadVisited[World::blockHash($x, $y, $z)];
|
||||
|
||||
unset($context->spreadVisited[World::blockHash($x, $y, $z)]);
|
||||
|
||||
@ -155,7 +156,11 @@ abstract class LightUpdate{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach(Facing::OFFSET as [$ox, $oy, $oz]){
|
||||
foreach(Facing::OFFSET as $side => [$ox, $oy, $oz]){
|
||||
if($from === $side){
|
||||
//don't check the side that this node received its initial light from
|
||||
continue;
|
||||
}
|
||||
$cx = $x + $ox;
|
||||
$cy = $y + $oy;
|
||||
$cz = $z + $oz;
|
||||
@ -169,7 +174,7 @@ abstract class LightUpdate{
|
||||
$lightArray = $this->getCurrentLightArray();
|
||||
}
|
||||
assert($subChunk !== null);
|
||||
$this->computeSpreadLight($cx, $cy, $cz, $newAdjacentLight, $context, $lightArray, $subChunk);
|
||||
$this->computeSpreadLight($cx, $cy, $cz, $newAdjacentLight, $context, $lightArray, $subChunk, $side);
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,7 +204,7 @@ abstract class LightUpdate{
|
||||
}
|
||||
}
|
||||
|
||||
protected function computeSpreadLight(int $x, int $y, int $z, int $newAdjacentLevel, LightPropagationContext $context, LightArray $lightArray, SubChunk $subChunk) : void{
|
||||
protected function computeSpreadLight(int $x, int $y, int $z, int $newAdjacentLevel, LightPropagationContext $context, LightArray $lightArray, SubChunk $subChunk, int $side) : void{
|
||||
$lx = $x & SubChunk::COORD_MASK;
|
||||
$ly = $y & SubChunk::COORD_MASK;
|
||||
$lz = $z & SubChunk::COORD_MASK;
|
||||
@ -210,7 +215,11 @@ abstract class LightUpdate{
|
||||
$lightArray->set($lx, $ly, $lz, $potentialLight);
|
||||
|
||||
if(!isset($context->spreadVisited[$index = World::blockHash($x, $y, $z)]) && $potentialLight > 1){
|
||||
$context->spreadVisited[$index] = true;
|
||||
//Track where this node was lit from, to avoid checking the source again when we propagate from here
|
||||
//TODO: In the future it might be worth tracking more than one adjacent source face in case multiple
|
||||
//nodes try to light the same node. However, this is a rare case since the vast majority of calls are
|
||||
//basic propagation with only one source anyway.
|
||||
$context->spreadVisited[$index] = Facing::opposite($side);
|
||||
$context->spreadQueue->enqueue([$x, $y, $z]);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -276,7 +276,7 @@ class ParserPacketHandler extends PacketHandler{
|
||||
$meta = $descriptor->getMeta();
|
||||
if($meta !== 32767){
|
||||
$blockStateId = $this->blockTranslator->getBlockStateDictionary()->lookupStateIdFromIdMeta($data->name, $meta);
|
||||
if($blockStateId !== null){
|
||||
if($this->blockItemIdMap->lookupBlockId($data->name) !== null && $blockStateId !== null){
|
||||
$blockState = $this->blockTranslator->getBlockStateDictionary()->generateDataFromStateId($blockStateId);
|
||||
if($blockState !== null && count($blockState->getStates()) > 0){
|
||||
$data->block_states = self::blockStatePropertiesToString($blockState);
|
||||
|
Loading…
x
Reference in New Issue
Block a user