mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-09 19:24:12 +00:00
Compare commits
240 Commits
dependabot
...
major-next
Author | SHA1 | Date | |
---|---|---|---|
47dac7244f | |||
9fcb16b6c1 | |||
1133d49c92 | |||
2f2c53067b | |||
66b8f2f160 | |||
1bc7cf340d | |||
25e937715e | |||
26cd5c471c | |||
e276fed3c8 | |||
82323cc7ca | |||
6610a19640 | |||
f91f5bff9b | |||
c61829ee19 | |||
3999a1f9f4 | |||
344d0af01b | |||
925b34e5c6 | |||
86c9adca7f | |||
644f73aa84 | |||
fa5cc3301c | |||
702733bdde | |||
b2d0be5b75 | |||
77ce07d065 | |||
d3c36e6287 | |||
e569cc3275 | |||
c931437a30 | |||
9a9506b793 | |||
06b48d97e9 | |||
851ac29f71 | |||
de7dcf114f | |||
dca9d3a010 | |||
4e82482a80 | |||
e87e6cf19f | |||
9310c46ea1 | |||
8dc4371385 | |||
7449ad5637 | |||
6aaf6b336a | |||
6f6b23d4e4 | |||
97027db70a | |||
aae88c5c26 | |||
24795eef0e | |||
1ebd7d3960 | |||
36211a96c1 | |||
e8eda19ae5 | |||
6d5c46b091 | |||
4e7077d169 | |||
237b304ef9 | |||
fc3f3d62f1 | |||
5ee081fbb1 | |||
b03804d1eb | |||
cd6199ad62 | |||
12f404b20d | |||
c65f740ce5 | |||
e630fc2dd6 | |||
79e3f2b281 | |||
7fbd868bc1 | |||
c02feba056 | |||
a3efaad328 | |||
98f0417611 | |||
afcd6b4e12 | |||
68126b308a | |||
e4b6f96535 | |||
f8ed7efb3f | |||
6340d12881 | |||
6d32ea5850 | |||
8229ee1812 | |||
950fb48bcb | |||
9e773ed439 | |||
6b5ff5016e | |||
215da7e3f4 | |||
c3ea6edc22 | |||
0330b25768 | |||
d5a1007c80 | |||
dca2665e17 | |||
05eda887b1 | |||
18b6b1742c | |||
b20d1b84b5 | |||
a8e898b13b | |||
d907d72e9b | |||
9d532b6e95 | |||
bb7bfee0cd | |||
88cdc2eb67 | |||
112bcf7af9 | |||
1c70cee72e | |||
7847524df6 | |||
1d26b21fe0 | |||
eb3922fc7e | |||
912a5d6ad0 | |||
2a42e2c75d | |||
3de604ef95 | |||
cb4364f8fd | |||
5bfa40618d | |||
8e1426e25e | |||
d86943fa8c | |||
baee0110c7 | |||
5617347949 | |||
0bbe56beb4 | |||
94caea97e0 | |||
ad95f392c1 | |||
9af3cde03f | |||
72f1391bd9 | |||
a90e5a6aa2 | |||
df5f87e309 | |||
510ef94698 | |||
d3f40b7b0c | |||
dae3e2b336 | |||
f2fa5933ea | |||
95a324755b | |||
1d13054608 | |||
ec140f7861 | |||
66f5bdcb94 | |||
5d24d8de0b | |||
1ad08e2432 | |||
a43ebcf217 | |||
c637d852e2 | |||
c58c64de85 | |||
694aa17cc9 | |||
c9441e1078 | |||
b0ac8863c4 | |||
e9df0baffb | |||
b3723b5b3e | |||
b370b5458f | |||
8af2d05ec0 | |||
4d186b52da | |||
e6ff55823f | |||
d556389b11 | |||
976fc63567 | |||
02ac512b4e | |||
708784b0a2 | |||
3f7f11b812 | |||
984e995659 | |||
46604b26f2 | |||
6b2fb9c4f8 | |||
80b761627a | |||
882d8c4ab9 | |||
1c35987ead | |||
88ae00fc4d | |||
47a1aa6470 | |||
3e69ee87e4 | |||
a2a2ec9d8b | |||
3a0f15ef0d | |||
7a2427ace2 | |||
f82c8dd3d3 | |||
851bbd7384 | |||
1ee52b69b0 | |||
851f7a9d80 | |||
6d2329128a | |||
07045dd424 | |||
c5b0df4578 | |||
5e9dbace90 | |||
205aabe11f | |||
3091e1325f | |||
779e80a961 | |||
007673cb96 | |||
0dae786a21 | |||
02d181d0c8 | |||
2fc6bbe84e | |||
002383be89 | |||
00bdb6be73 | |||
c3c917bb05 | |||
a078f653f4 | |||
ed33983792 | |||
15eaf67a0c | |||
d72941c36c | |||
e51903d7ea | |||
3e9a96b43a | |||
9fce27eaa8 | |||
7208733d62 | |||
c61434d87b | |||
dcc258706f | |||
820e2d4a2f | |||
0fb1415f7f | |||
a6534ecbbb | |||
330bcd2423 | |||
e71b9e8dc6 | |||
9e2d91bae6 | |||
b6f55b78a9 | |||
ab5176baf9 | |||
ef6fce4091 | |||
cc335889f3 | |||
80b7f6aba4 | |||
82c5a3160c | |||
85de28d6c3 | |||
1ef854f2d1 | |||
082af9978c | |||
e8620ef94d | |||
83a91634c3 | |||
3c73bd22dd | |||
0e1824451b | |||
6c5ae634fd | |||
041944ed16 | |||
603527c6e8 | |||
1ac08ea73b | |||
c9e8d382c5 | |||
12179aa03a | |||
e781c64540 | |||
644693ffee | |||
6b66cbfb1c | |||
4d337add7c | |||
9d75c45bf5 | |||
c7a537abbb | |||
54694df48c | |||
15aae721cd | |||
d565be93a8 | |||
e32a90be72 | |||
d4d7d02067 | |||
a45e143e81 | |||
05981d2669 | |||
fa9bba470c | |||
361626d236 | |||
16d8522245 | |||
a4f3476190 | |||
e96e68d221 | |||
f1a6d71cc1 | |||
89f42c80d4 | |||
cd6b780d31 | |||
ed61a68013 | |||
4dc9d696d0 | |||
258038c9a9 | |||
5c915a3dfe | |||
8c594fd126 | |||
9fd6653f36 | |||
32d67080e5 | |||
ed9d057ca2 | |||
5ec0e0f20b | |||
cb251069dd | |||
e0ad39b70a | |||
9997b614bc | |||
89f8f421a6 | |||
c4ff6d7757 | |||
3c0e7ae492 | |||
b944205f60 | |||
2ab3393568 | |||
1e1b95e1b8 | |||
62465fa676 | |||
aac5944396 | |||
74cfd687d7 | |||
f2f30143b0 | |||
d98adf127f | |||
280bf60830 | |||
1ffa945fbf |
2
.github/workflows/discord-release-notify.yml
vendored
2
.github/workflows/discord-release-notify.yml
vendored
@ -20,7 +20,7 @@ jobs:
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.35.4
|
||||
with:
|
||||
php-version: 8.2
|
||||
php-version: 8.3
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v4
|
||||
|
2
.github/workflows/draft-release-pr-check.yml
vendored
2
.github/workflows/draft-release-pr-check.yml
vendored
@ -51,7 +51,7 @@ jobs:
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@2.35.4
|
||||
with:
|
||||
php-version: 8.2
|
||||
php-version: 8.3
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v4
|
||||
|
2
.github/workflows/draft-release.yml
vendored
2
.github/workflows/draft-release.yml
vendored
@ -18,7 +18,7 @@ on:
|
||||
- "*"
|
||||
|
||||
env:
|
||||
PHP_VERSION: "8.2"
|
||||
PHP_VERSION: "8.3"
|
||||
|
||||
jobs:
|
||||
skip:
|
||||
|
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@ -11,7 +11,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php: ["8.1", "8.2", "8.3", "8.4"]
|
||||
php: ["8.3", "8.4"]
|
||||
|
||||
uses: ./.github/workflows/main-php-matrix.yml
|
||||
with:
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,6 +1,3 @@
|
||||
[submodule "tests/plugins/DevTools"]
|
||||
path = tests/plugins/DevTools
|
||||
url = https://github.com/pmmp/DevTools.git
|
||||
[submodule "build/php"]
|
||||
path = build/php
|
||||
url = https://github.com/pmmp/php-build-scripts.git
|
||||
|
@ -5,7 +5,7 @@ $finder = PhpCsFixer\Finder::create()
|
||||
->in(__DIR__ . '/build')
|
||||
->in(__DIR__ . '/tests')
|
||||
->in(__DIR__ . '/tools')
|
||||
->notPath('plugins/DevTools')
|
||||
|
||||
//JsonMapper will break if the FQNs in the doc comments for these are shortened :(
|
||||
->notPath('crafting/json')
|
||||
->notPath('inventory/json')
|
||||
|
@ -5,7 +5,7 @@
|
||||
"homepage": "https://pmmp.io",
|
||||
"license": "LGPL-3.0",
|
||||
"require": {
|
||||
"php": "^8.1",
|
||||
"php": "^8.3",
|
||||
"php-64bit": "*",
|
||||
"ext-chunkutils2": "^0.3.1",
|
||||
"ext-crypto": "^0.3.1",
|
||||
@ -38,24 +38,24 @@
|
||||
"pocketmine/bedrock-item-upgrade-schema": "~1.15.0+bedrock-1.21.100",
|
||||
"pocketmine/bedrock-protocol": "~40.0.0+bedrock-1.21.100",
|
||||
"pocketmine/binaryutils": "^0.2.1",
|
||||
"pocketmine/callback-validator": "^1.0.2",
|
||||
"pocketmine/callback-validator": "dev-rewrite",
|
||||
"pocketmine/color": "^0.3.0",
|
||||
"pocketmine/errorhandler": "^0.7.0",
|
||||
"pocketmine/locale-data": "~2.25.0",
|
||||
"pocketmine/log": "^0.4.0",
|
||||
"pocketmine/math": "~1.0.0",
|
||||
"pocketmine/math": "dev-major-next as 1.0.0",
|
||||
"pocketmine/nbt": "~1.1.0",
|
||||
"pocketmine/raklib": "~1.2.0",
|
||||
"pocketmine/raklib-ipc": "~1.0.0",
|
||||
"pocketmine/snooze": "^0.5.0",
|
||||
"ramsey/uuid": "~4.9.0",
|
||||
"symfony/filesystem": "~6.4.0"
|
||||
"symfony/filesystem": "~7.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "2.1.17",
|
||||
"phpstan/phpstan-phpunit": "^2.0.0",
|
||||
"phpstan/phpstan-strict-rules": "^2.0.0",
|
||||
"phpunit/phpunit": "^10.5.24"
|
||||
"phpunit/phpunit": "^12.2.1"
|
||||
},
|
||||
"replace": {
|
||||
"symfony/polyfill-ctype": "*",
|
||||
@ -77,12 +77,11 @@
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "8.1.0"
|
||||
"php": "8.3.0"
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
"scripts": {
|
||||
"make-devtools": "@php -dphar.readonly=0 tests/plugins/DevTools/src/ConsoleScript.php --make ./ --relative tests/plugins/DevTools --out plugins/DevTools.phar",
|
||||
"make-server": [
|
||||
"@composer install --no-dev --classmap-authoritative --ignore-platform-reqs",
|
||||
"@php -dphar.readonly=0 build/server-phar.php"
|
||||
|
737
composer.lock
generated
737
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,6 @@ includes:
|
||||
- tests/phpstan/analyse-for-current-php-version.neon.php
|
||||
- tests/phpstan/configs/actual-problems.neon
|
||||
- tests/phpstan/configs/impossible-generics.neon
|
||||
- tests/phpstan/configs/php-bugs.neon
|
||||
- tests/phpstan/configs/phpstan-bugs.neon
|
||||
- tests/phpstan/configs/property-hook-sadness.neon
|
||||
- tests/phpstan/configs/reflection-class-sadness.neon
|
||||
@ -12,9 +11,7 @@ includes:
|
||||
- vendor/phpstan/phpstan-strict-rules/rules.neon
|
||||
|
||||
rules:
|
||||
- pocketmine\phpstan\rules\DeprecatedLegacyEnumAccessRule
|
||||
- pocketmine\phpstan\rules\DisallowDynamicNewRule
|
||||
- pocketmine\phpstan\rules\DisallowEnumComparisonRule
|
||||
- pocketmine\phpstan\rules\DisallowForeachByReferenceRule
|
||||
- pocketmine\phpstan\rules\ExplodeLimitRule
|
||||
- pocketmine\phpstan\rules\UnsafeForeachRule
|
||||
|
@ -123,13 +123,6 @@ class MemoryManager{
|
||||
return $this->globalMemoryLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function canUseChunkCache() : bool{
|
||||
return !$this->lowMemory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the allowed chunk radius based on the current memory usage.
|
||||
*/
|
||||
@ -236,13 +229,4 @@ class MemoryManager{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Static memory dumper accessible from any thread.
|
||||
* @deprecated
|
||||
* @see MemoryDump
|
||||
*/
|
||||
public static function dumpMemory(mixed $startingObject, string $outputFolder, int $maxNesting, int $maxStringSize, \Logger $logger) : void{
|
||||
MemoryDump::dumpMemory($startingObject, $outputFolder, $maxNesting, $maxStringSize, $logger);
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ namespace pocketmine {
|
||||
|
||||
require_once __DIR__ . '/VersionInfo.php';
|
||||
|
||||
const MIN_PHP_VERSION = "8.1.0";
|
||||
const MIN_PHP_VERSION = "8.3.0";
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
|
@ -80,6 +80,7 @@ use pocketmine\player\PlayerDataLoadException;
|
||||
use pocketmine\player\PlayerDataProvider;
|
||||
use pocketmine\player\PlayerDataSaveException;
|
||||
use pocketmine\player\PlayerInfo;
|
||||
use pocketmine\plugin\FolderPluginLoader;
|
||||
use pocketmine\plugin\PharPluginLoader;
|
||||
use pocketmine\plugin\PluginEnableOrder;
|
||||
use pocketmine\plugin\PluginGraylist;
|
||||
@ -346,6 +347,10 @@ class Server{
|
||||
return $this->maxPlayers;
|
||||
}
|
||||
|
||||
public function setMaxPlayers(int $maxPlayers) : void{
|
||||
$this->maxPlayers = $maxPlayers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the server requires that players be authenticated to Xbox Live. If true, connecting players who
|
||||
* are not logged into Xbox Live will be disconnected.
|
||||
@ -1029,6 +1034,7 @@ class Server{
|
||||
$this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool(Yml::PLUGINS_LEGACY_DATA_DIR, true) ? null : Path::join($this->dataPath, "plugin_data"), $pluginGraylist);
|
||||
$this->pluginManager->registerInterface(new PharPluginLoader($this->autoloader));
|
||||
$this->pluginManager->registerInterface(new ScriptPluginLoader());
|
||||
$this->pluginManager->registerInterface(new FolderPluginLoader($this->autoloader));
|
||||
|
||||
$providerManager = new WorldProviderManager();
|
||||
if(
|
||||
|
@ -82,22 +82,22 @@ final class AmethystCluster extends Transparent implements AnyFacing{
|
||||
if($axis === $myAxis){
|
||||
continue;
|
||||
}
|
||||
$box->squash($axis, $this->stage === self::STAGE_SMALL_BUD ? 4 / 16 : 3 / 16);
|
||||
$box = $box->squashedCopy($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));
|
||||
$box = $box->trimmedCopy($this->facing, 1 - ($this->stage === self::STAGE_CLUSTER ? 7 / 16 : ($this->stage + 3) / 16));
|
||||
|
||||
return [$box];
|
||||
}
|
||||
|
||||
private function canBeSupportedAt(Block $block, int $facing) : bool{
|
||||
private function canBeSupportedAt(Block $block, Facing $facing) : bool{
|
||||
return $block->getAdjacentSupportType($facing) === SupportType::FULL;
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$this->canBeSupportedAt($blockReplace, Facing::opposite($face))){
|
||||
return false;
|
||||
}
|
||||
|
@ -23,11 +23,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\inventory\AnvilInventory;
|
||||
use pocketmine\block\inventory\window\AnvilInventoryWindow;
|
||||
use pocketmine\block\utils\Fallable;
|
||||
use pocketmine\block\utils\FallableTrait;
|
||||
use pocketmine\block\utils\HorizontalFacing;
|
||||
use pocketmine\block\utils\HorizontalFacingOption;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\MenuAccessor;
|
||||
use pocketmine\block\utils\MenuAccessorTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\entity\object\FallingBlock;
|
||||
@ -38,13 +41,15 @@ use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\Position;
|
||||
use pocketmine\world\sound\AnvilFallSound;
|
||||
use pocketmine\world\sound\Sound;
|
||||
use function round;
|
||||
|
||||
class Anvil extends Transparent implements Fallable, HorizontalFacing{
|
||||
class Anvil extends Transparent implements Fallable, HorizontalFacing, MenuAccessor{
|
||||
use FallableTrait;
|
||||
use HorizontalFacingTrait;
|
||||
use MenuAccessorTrait;
|
||||
|
||||
public const UNDAMAGED = 0;
|
||||
public const SLIGHTLY_DAMAGED = 1;
|
||||
@ -57,7 +62,7 @@ class Anvil extends Transparent implements Fallable, HorizontalFacing{
|
||||
}
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->horizontalFacing($this->facing);
|
||||
$w->enum($this->facing);
|
||||
}
|
||||
|
||||
public function getDamage() : int{ return $this->damage; }
|
||||
@ -72,24 +77,20 @@ class Anvil extends Transparent implements Fallable, HorizontalFacing{
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->squash(Facing::axis(Facing::rotateY($this->facing, false)), 1 / 8)];
|
||||
return [AxisAlignedBB::one()->squashedCopy(Facing::axis(Facing::rotateY($this->facing->toFacing(), false)), 1 / 8)];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($player instanceof Player){
|
||||
$player->setCurrentWindow(new AnvilInventory($this->position));
|
||||
}
|
||||
|
||||
return true;
|
||||
protected function newMenu(Player $player, Position $position) : AnvilInventoryWindow{
|
||||
return new AnvilInventoryWindow($player, $position);
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($player !== null){
|
||||
$this->facing = Facing::rotateY($player->getHorizontalFacing(), false);
|
||||
$this->facing = HorizontalFacingOption::fromFacing(Facing::rotateY($player->getHorizontalFacing(), false));
|
||||
}
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
@ -90,10 +90,10 @@ class Bamboo extends Transparent{
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
//this places the BB at the northwest corner, not the center
|
||||
$inset = 1 - (($this->thick ? 3 : 2) / 16);
|
||||
return [AxisAlignedBB::one()->trim(Facing::SOUTH, $inset)->trim(Facing::EAST, $inset)];
|
||||
return [AxisAlignedBB::one()->trimmedCopy(Facing::SOUTH, $inset)->trimmedCopy(Facing::EAST, $inset)];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
@ -138,7 +138,7 @@ class Bamboo extends Transparent{
|
||||
return $top;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item instanceof Fertilizer){
|
||||
$top = $this->seekToTop();
|
||||
if($top->grow(self::getMaxHeight($top->position->getFloorX(), $top->position->getFloorZ()), mt_rand(1, 2), $player)){
|
||||
|
@ -61,7 +61,7 @@ final class BambooSapling extends Flowable{
|
||||
$supportBlock->hasTypeTag(BlockTypeTags::SAND);
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item instanceof Fertilizer || $item instanceof ItemBamboo){
|
||||
if($this->grow($player)){
|
||||
$item->pop();
|
||||
|
@ -23,24 +23,33 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\tile\Barrel as TileBarrel;
|
||||
use pocketmine\block\utils\AnimatedContainerLike;
|
||||
use pocketmine\block\utils\AnimatedContainerLikeTrait;
|
||||
use pocketmine\block\utils\AnyFacing;
|
||||
use pocketmine\block\utils\AnyFacingTrait;
|
||||
use pocketmine\block\utils\Container;
|
||||
use pocketmine\block\utils\ContainerTrait;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\Position;
|
||||
use pocketmine\world\sound\BarrelCloseSound;
|
||||
use pocketmine\world\sound\BarrelOpenSound;
|
||||
use pocketmine\world\sound\Sound;
|
||||
use function abs;
|
||||
|
||||
class Barrel extends Opaque implements AnyFacing{
|
||||
class Barrel extends Opaque implements AnimatedContainerLike, AnyFacing, Container{
|
||||
use AnimatedContainerLikeTrait;
|
||||
use AnyFacingTrait;
|
||||
use ContainerTrait;
|
||||
|
||||
protected bool $open = false;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->facing($this->facing);
|
||||
$w->enum($this->facing);
|
||||
$w->bool($this->open);
|
||||
}
|
||||
|
||||
@ -54,7 +63,7 @@ class Barrel extends Opaque implements AnyFacing{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($player !== null){
|
||||
if(abs($player->getPosition()->x - $this->position->x) < 2 && abs($player->getPosition()->z - $this->position->z) < 2){
|
||||
$y = $player->getEyePos()->y;
|
||||
@ -74,22 +83,23 @@ class Barrel extends Opaque implements AnyFacing{
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($player instanceof Player){
|
||||
$barrel = $this->position->getWorld()->getTile($this->position);
|
||||
if($barrel instanceof TileBarrel){
|
||||
if(!$barrel->canOpenWith($item->getCustomName())){
|
||||
return true;
|
||||
}
|
||||
|
||||
$player->setCurrentWindow($barrel->getInventory());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getFuelTime() : int{
|
||||
return 300;
|
||||
}
|
||||
|
||||
protected function getOpenSound() : Sound{
|
||||
return new BarrelOpenSound();
|
||||
}
|
||||
|
||||
protected function getCloseSound() : Sound{
|
||||
return new BarrelCloseSound();
|
||||
}
|
||||
|
||||
protected function playAnimationVisual(Position $position, bool $isOpen) : void{
|
||||
$world = $position->getWorld();
|
||||
$block = $world->getBlock($position);
|
||||
if($block instanceof Barrel){
|
||||
$world->setBlock($position, $block->setOpen($isOpen));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\item\Banner as ItemBanner;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
@ -112,7 +113,7 @@ abstract class BaseBanner extends Transparent implements Colored{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
@ -120,7 +121,7 @@ abstract class BaseBanner extends Transparent implements Colored{
|
||||
return $block->isSolid();
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$this->canBeSupportedBy($blockReplace->getSide($this->getSupportingFace()))){
|
||||
return false;
|
||||
}
|
||||
@ -132,7 +133,7 @@ abstract class BaseBanner extends Transparent implements Colored{
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
abstract protected function getSupportingFace() : int;
|
||||
abstract protected function getSupportingFace() : Facing;
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(!$this->canBeSupportedBy($this->getSide($this->getSupportingFace()))){
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\HorizontalFacing;
|
||||
use pocketmine\block\utils\HorizontalFacingOption;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\event\block\StructureGrowEvent;
|
||||
@ -57,13 +58,13 @@ abstract class BaseBigDripleaf extends Transparent implements HorizontalFacing{
|
||||
}
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$block = $blockReplace->getSide(Facing::DOWN);
|
||||
if(!$this->canBeSupportedBy($block, true)){
|
||||
return false;
|
||||
}
|
||||
if($player !== null){
|
||||
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
||||
$this->facing = HorizontalFacingOption::fromFacing(Facing::opposite($player->getHorizontalFacing()));
|
||||
}
|
||||
if($block instanceof BaseBigDripleaf){
|
||||
$this->facing = $block->facing;
|
||||
@ -72,7 +73,7 @@ abstract class BaseBigDripleaf extends Transparent implements HorizontalFacing{
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item instanceof Fertilizer && $this->grow($player)){
|
||||
$item->pop();
|
||||
return true;
|
||||
@ -131,7 +132,7 @@ abstract class BaseBigDripleaf extends Transparent implements HorizontalFacing{
|
||||
return 100;
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ use pocketmine\player\Player;
|
||||
abstract class BaseCake extends Transparent implements FoodSource{
|
||||
use StaticSupportTrait;
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ abstract class BaseCake extends Transparent implements FoodSource{
|
||||
return $block->getSide(Facing::DOWN)->getTypeId() !== BlockTypeIds::AIR;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($player !== null){
|
||||
return $player->consumeObject($this);
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ use pocketmine\block\utils\CoralMaterial;
|
||||
use pocketmine\block\utils\CoralTypeTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use function mt_rand;
|
||||
|
||||
abstract class BaseCoral extends Transparent implements CoralMaterial{
|
||||
@ -72,7 +73,7 @@ abstract class BaseCoral extends Transparent implements CoralMaterial{
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{ return []; }
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ use pocketmine\block\utils\DyeColor;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
@ -60,7 +61,7 @@ abstract class BaseOminousBanner extends Transparent{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
@ -68,7 +69,7 @@ abstract class BaseOminousBanner extends Transparent{
|
||||
return $block->isSolid();
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$this->canBeSupportedBy($blockReplace->getSide($this->getSupportingFace()))){
|
||||
return false;
|
||||
}
|
||||
@ -76,7 +77,7 @@ abstract class BaseOminousBanner extends Transparent{
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
abstract protected function getSupportingFace() : int;
|
||||
abstract protected function getSupportingFace() : Facing;
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(!$this->canBeSupportedBy($this->getSide($this->getSupportingFace()))){
|
||||
|
@ -37,7 +37,7 @@ use function in_array;
|
||||
|
||||
abstract class BaseRail extends Flowable{
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($blockReplace->getAdjacentSupportType(Facing::DOWN)->hasEdgeSupport()){
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
@ -89,8 +89,9 @@ abstract class BaseRail extends Flowable{
|
||||
|
||||
/** @var int $connection */
|
||||
foreach($this->getCurrentShapeConnections() as $connection){
|
||||
$other = $this->getSide($connection & ~RailConnectionInfo::FLAG_ASCEND);
|
||||
$otherConnection = Facing::opposite($connection & ~RailConnectionInfo::FLAG_ASCEND);
|
||||
$connectionFace = Facing::from($connection & ~RailConnectionInfo::FLAG_ASCEND);
|
||||
$other = $this->getSide($connectionFace);
|
||||
$otherConnection = Facing::opposite($connectionFace)->value;
|
||||
|
||||
if(($connection & RailConnectionInfo::FLAG_ASCEND) !== 0){
|
||||
$other = $other->getSide(Facing::UP);
|
||||
@ -122,10 +123,10 @@ abstract class BaseRail extends Flowable{
|
||||
case 0:
|
||||
//No constraints, can connect in any direction
|
||||
$possible = [
|
||||
Facing::NORTH => true,
|
||||
Facing::SOUTH => true,
|
||||
Facing::WEST => true,
|
||||
Facing::EAST => true
|
||||
Facing::NORTH->value => true,
|
||||
Facing::SOUTH->value => true,
|
||||
Facing::WEST->value => true,
|
||||
Facing::EAST->value => true
|
||||
];
|
||||
foreach($possible as $p => $_){
|
||||
$possible[$p | RailConnectionInfo::FLAG_ASCEND] = true;
|
||||
@ -146,13 +147,13 @@ abstract class BaseRail extends Flowable{
|
||||
* @phpstan-return array<int, true>
|
||||
*/
|
||||
protected function getPossibleConnectionDirectionsOneConstraint(int $constraint) : array{
|
||||
$opposite = Facing::opposite($constraint & ~RailConnectionInfo::FLAG_ASCEND);
|
||||
$opposite = Facing::opposite(Facing::from($constraint & ~RailConnectionInfo::FLAG_ASCEND));
|
||||
|
||||
$possible = [$opposite => true];
|
||||
$possible = [$opposite->value => true];
|
||||
|
||||
if(($constraint & RailConnectionInfo::FLAG_ASCEND) === 0){
|
||||
//We can slope the other way if this connection isn't already a slope
|
||||
$possible[$opposite | RailConnectionInfo::FLAG_ASCEND] = true;
|
||||
$possible[$opposite->value | RailConnectionInfo::FLAG_ASCEND] = true;
|
||||
}
|
||||
|
||||
return $possible;
|
||||
@ -168,9 +169,10 @@ abstract class BaseRail extends Flowable{
|
||||
$continue = false;
|
||||
|
||||
foreach($possible as $thisSide => $_){
|
||||
$otherSide = Facing::opposite($thisSide & ~RailConnectionInfo::FLAG_ASCEND);
|
||||
$thisSideEnum = Facing::from($thisSide & ~RailConnectionInfo::FLAG_ASCEND);
|
||||
$otherSide = Facing::opposite($thisSideEnum)->value;
|
||||
|
||||
$other = $this->getSide($thisSide & ~RailConnectionInfo::FLAG_ASCEND);
|
||||
$other = $this->getSide($thisSideEnum);
|
||||
|
||||
if(($thisSide & RailConnectionInfo::FLAG_ASCEND) !== 0){
|
||||
$other = $other->getSide(Facing::UP);
|
||||
@ -212,7 +214,7 @@ abstract class BaseRail extends Flowable{
|
||||
*/
|
||||
private function setConnections(array $connections) : void{
|
||||
if(count($connections) === 1){
|
||||
$connections[] = Facing::opposite($connections[0] & ~RailConnectionInfo::FLAG_ASCEND);
|
||||
$connections[] = Facing::opposite(Facing::from($connections[0] & ~RailConnectionInfo::FLAG_ASCEND))->value;
|
||||
}elseif(count($connections) !== 2){
|
||||
throw new \InvalidArgumentException("Expected exactly 2 connections, got " . count($connections));
|
||||
}
|
||||
@ -226,7 +228,7 @@ abstract class BaseRail extends Flowable{
|
||||
$world->useBreakOn($this->position);
|
||||
}else{
|
||||
foreach($this->getCurrentShapeConnections() as $connection){
|
||||
if(($connection & RailConnectionInfo::FLAG_ASCEND) !== 0 && !$this->getSide($connection & ~RailConnectionInfo::FLAG_ASCEND)->getSupportType(Facing::UP)->hasEdgeSupport()){
|
||||
if(($connection & RailConnectionInfo::FLAG_ASCEND) !== 0 && !$this->getSide(Facing::from($connection & ~RailConnectionInfo::FLAG_ASCEND))->getSupportType(Facing::UP)->hasEdgeSupport()){
|
||||
$world->useBreakOn($this->position);
|
||||
break;
|
||||
}
|
||||
|
@ -35,20 +35,26 @@ use pocketmine\event\block\SignChangeEvent;
|
||||
use pocketmine\item\Dye;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemTypeIds;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\sound\DyeUseSound;
|
||||
use pocketmine\world\sound\InkSacUseSound;
|
||||
use function abs;
|
||||
use function array_map;
|
||||
use function assert;
|
||||
use function atan2;
|
||||
use function fmod;
|
||||
use function rad2deg;
|
||||
use function strlen;
|
||||
|
||||
abstract class BaseSign extends Transparent implements WoodMaterial{
|
||||
use WoodTypeTrait;
|
||||
|
||||
protected SignText $text;
|
||||
protected SignText $text; //TODO: rename this (BC break)
|
||||
protected SignText $backText;
|
||||
private bool $waxed = false;
|
||||
|
||||
protected ?int $editorEntityRuntimeId = null;
|
||||
@ -63,6 +69,7 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
|
||||
$this->woodType = $woodType;
|
||||
parent::__construct($idInfo, $name, $typeInfo);
|
||||
$this->text = new SignText();
|
||||
$this->backText = new SignText();
|
||||
$this->asItemCallback = $asItemCallback;
|
||||
}
|
||||
|
||||
@ -71,6 +78,7 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
|
||||
$tile = $this->position->getWorld()->getTile($this->position);
|
||||
if($tile instanceof TileSign){
|
||||
$this->text = $tile->getText();
|
||||
$this->backText = $tile->getBackText();
|
||||
$this->waxed = $tile->isWaxed();
|
||||
$this->editorEntityRuntimeId = $tile->getEditorEntityRuntimeId();
|
||||
}
|
||||
@ -83,6 +91,7 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
|
||||
$tile = $this->position->getWorld()->getTile($this->position);
|
||||
assert($tile instanceof TileSign);
|
||||
$tile->setText($this->text);
|
||||
$tile->setBackText($this->backText);
|
||||
$tile->setWaxed($this->waxed);
|
||||
$tile->setEditorEntityRuntimeId($this->editorEntityRuntimeId);
|
||||
}
|
||||
@ -99,11 +108,11 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
abstract protected function getSupportingFace() : int;
|
||||
abstract protected function getSupportingFace() : Facing;
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide($this->getSupportingFace())->getTypeId() === BlockTypeIds::AIR){
|
||||
@ -111,7 +120,7 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
|
||||
}
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($player !== null){
|
||||
$this->editorEntityRuntimeId = $player->getId();
|
||||
}
|
||||
@ -127,11 +136,11 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
|
||||
}
|
||||
}
|
||||
|
||||
private function doSignChange(SignText $newText, Player $player, Item $item) : bool{
|
||||
$ev = new SignChangeEvent($this, $player, $newText);
|
||||
private function doSignChange(SignText $newText, Player $player, Item $item, bool $frontFace) : bool{
|
||||
$ev = new SignChangeEvent($this, $player, $newText, $frontFace);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->text = $ev->getNewText();
|
||||
$this->setFaceText($frontFace, $ev->getNewText());
|
||||
$this->position->getWorld()->setBlock($this->position, $this);
|
||||
$item->pop();
|
||||
return true;
|
||||
@ -140,8 +149,9 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
|
||||
return false;
|
||||
}
|
||||
|
||||
private function changeSignGlowingState(bool $glowing, Player $player, Item $item) : bool{
|
||||
if($this->text->isGlowing() !== $glowing && $this->doSignChange(new SignText($this->text->getLines(), $this->text->getBaseColor(), $glowing), $player, $item)){
|
||||
private function changeSignGlowingState(bool $glowing, Player $player, Item $item, bool $frontFace) : bool{
|
||||
$text = $this->getFaceText($frontFace);
|
||||
if($text->isGlowing() !== $glowing && $this->doSignChange(new SignText($text->getLines(), $text->getBaseColor(), $glowing), $player, $item, $frontFace)){
|
||||
$this->position->getWorld()->addSound($this->position, new InkSacUseSound());
|
||||
return true;
|
||||
}
|
||||
@ -160,7 +170,7 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($player === null){
|
||||
return false;
|
||||
}
|
||||
@ -168,6 +178,8 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
|
||||
return true;
|
||||
}
|
||||
|
||||
$frontFace = $this->interactsFront($this->getHitboxCenter(), $player->getPosition(), $this->getFacingDegrees());
|
||||
|
||||
$dyeColor = $item instanceof Dye ? $item->getColor() : match($item->getTypeId()){
|
||||
ItemTypeIds::BONE_MEAL => DyeColor::WHITE,
|
||||
ItemTypeIds::LAPIS_LAZULI => DyeColor::BLUE,
|
||||
@ -176,40 +188,82 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
|
||||
};
|
||||
if($dyeColor !== null){
|
||||
$color = $dyeColor === DyeColor::BLACK ? new Color(0, 0, 0) : $dyeColor->getRgbValue();
|
||||
$text = $this->getFaceText($frontFace);
|
||||
if(
|
||||
$color->toARGB() !== $this->text->getBaseColor()->toARGB() &&
|
||||
$this->doSignChange(new SignText($this->text->getLines(), $color, $this->text->isGlowing()), $player, $item)
|
||||
$color->toARGB() !== $text->getBaseColor()->toARGB() &&
|
||||
$this->doSignChange(new SignText($text->getLines(), $color, $text->isGlowing()), $player, $item, $frontFace)
|
||||
){
|
||||
$this->position->getWorld()->addSound($this->position, new DyeUseSound());
|
||||
return true;
|
||||
}
|
||||
}elseif(match($item->getTypeId()){
|
||||
ItemTypeIds::INK_SAC => $this->changeSignGlowingState(false, $player, $item),
|
||||
ItemTypeIds::GLOW_INK_SAC => $this->changeSignGlowingState(true, $player, $item),
|
||||
ItemTypeIds::INK_SAC => $this->changeSignGlowingState(false, $player, $item, $frontFace),
|
||||
ItemTypeIds::GLOW_INK_SAC => $this->changeSignGlowingState(true, $player, $item, $frontFace),
|
||||
ItemTypeIds::HONEYCOMB => $this->wax($player, $item),
|
||||
default => false
|
||||
}){
|
||||
return true;
|
||||
}
|
||||
|
||||
$player->openSignEditor($this->position);
|
||||
$player->openSignEditor($this->position, $frontFace);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function interactsFront(Vector3 $hitboxCenter, Vector3 $playerPosition, float $signFacingDegrees) : bool{
|
||||
$playerCenterDiffX = $playerPosition->x - $hitboxCenter->x;
|
||||
$playerCenterDiffZ = $playerPosition->z - $hitboxCenter->z;
|
||||
|
||||
$f1 = rad2deg(atan2($playerCenterDiffZ, $playerCenterDiffX)) - 90.0;
|
||||
|
||||
$rotationDiff = $signFacingDegrees - $f1;
|
||||
$rotation = fmod($rotationDiff + 180.0, 360.0) - 180.0; // Normalize to [-180, 180]
|
||||
return abs($rotation) <= 90.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the center of the sign's hitbox. Used to decide which face of the sign to open when a player interacts.
|
||||
*/
|
||||
protected function getHitboxCenter() : Vector3{
|
||||
return $this->position->add(0.5, 0.5, 0.5);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: make this abstract (BC break)
|
||||
*/
|
||||
protected function getFacingDegrees() : float{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object containing information about the sign text.
|
||||
* @deprecated
|
||||
* @see self::getFaceText()
|
||||
*/
|
||||
public function getText() : SignText{
|
||||
return $this->text;
|
||||
}
|
||||
|
||||
/** @return $this */
|
||||
/**
|
||||
* @deprecated
|
||||
* @see self::setFaceText()
|
||||
* @return $this
|
||||
*/
|
||||
public function setText(SignText $text) : self{
|
||||
$this->text = $text;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFaceText(bool $frontFace) : SignText{
|
||||
return $frontFace ? $this->text : $this->backText;
|
||||
}
|
||||
|
||||
/** @return $this */
|
||||
public function setFaceText(bool $frontFace, SignText $text) : self{
|
||||
$frontFace ? $this->text = $text : $this->backText = $text;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the sign has been waxed using a honeycomb. If true, the sign cannot be edited by a player.
|
||||
*/
|
||||
@ -234,13 +288,21 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @see self::updateFaceText()
|
||||
*/
|
||||
public function updateText(Player $author, SignText $text) : bool{
|
||||
return $this->updateFaceText($author, true, $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the player controller (network session) to update the sign text, firing events as appropriate.
|
||||
*
|
||||
* @return bool if the sign update was successful.
|
||||
* @throws \UnexpectedValueException if the text payload is too large
|
||||
*/
|
||||
public function updateText(Player $author, SignText $text) : bool{
|
||||
public function updateFaceText(Player $author, bool $frontFace, SignText $text) : bool{
|
||||
$size = 0;
|
||||
foreach($text->getLines() as $line){
|
||||
$size += strlen($line);
|
||||
@ -248,15 +310,16 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
|
||||
if($size > 1000){
|
||||
throw new \UnexpectedValueException($author->getName() . " tried to write $size bytes of text onto a sign (bigger than max 1000)");
|
||||
}
|
||||
$oldText = $this->getFaceText($frontFace);
|
||||
$ev = new SignChangeEvent($this, $author, new SignText(array_map(function(string $line) : string{
|
||||
return TextFormat::clean($line, false);
|
||||
}, $text->getLines()), $this->text->getBaseColor(), $this->text->isGlowing()));
|
||||
}, $text->getLines()), $oldText->getBaseColor(), $oldText->isGlowing()), $frontFace);
|
||||
if($this->waxed || $this->editorEntityRuntimeId !== $author->getId()){
|
||||
$ev->cancel();
|
||||
}
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->setText($ev->getNewText());
|
||||
$this->setFaceText($frontFace, $ev->getNewText());
|
||||
$this->setEditorEntityRuntimeId(null);
|
||||
$this->position->getWorld()->setBlock($this->position, $this);
|
||||
return true;
|
||||
|
@ -28,6 +28,7 @@ use pocketmine\block\utils\Colored;
|
||||
use pocketmine\block\utils\ColoredTrait;
|
||||
use pocketmine\block\utils\DyeColor;
|
||||
use pocketmine\block\utils\HorizontalFacing;
|
||||
use pocketmine\block\utils\HorizontalFacingOption;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
@ -51,7 +52,7 @@ class Bed extends Transparent implements Colored, HorizontalFacing{
|
||||
protected bool $head = false;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->horizontalFacing($this->facing);
|
||||
$w->enum($this->facing);
|
||||
$w->bool($this->occupied);
|
||||
$w->bool($this->head);
|
||||
}
|
||||
@ -79,10 +80,10 @@ class Bed extends Transparent implements Colored, HorizontalFacing{
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->trim(Facing::UP, 7 / 16)];
|
||||
return [AxisAlignedBB::one()->trimmedCopy(Facing::UP, 7 / 16)];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
@ -106,8 +107,8 @@ class Bed extends Transparent implements Colored, HorizontalFacing{
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function getOtherHalfSide() : int{
|
||||
return $this->head ? Facing::opposite($this->facing) : $this->facing;
|
||||
private function getOtherHalfSide() : Facing{
|
||||
return $this->head ? Facing::opposite($this->facing->toFacing()) : $this->facing->toFacing();
|
||||
}
|
||||
|
||||
public function getOtherHalf() : ?Bed{
|
||||
@ -119,7 +120,7 @@ class Bed extends Transparent implements Colored, HorizontalFacing{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($player !== null){
|
||||
$other = $this->getOtherHalf();
|
||||
$playerPos = $player->getPosition();
|
||||
@ -172,9 +173,11 @@ class Bed extends Transparent implements Colored, HorizontalFacing{
|
||||
return $entity->getMotion()->y * -3 / 4; // 2/3 in Java, according to the wiki
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($this->canBeSupportedAt($blockReplace)){
|
||||
$this->facing = $player !== null ? $player->getHorizontalFacing() : Facing::NORTH;
|
||||
if($player !== null){
|
||||
$this->facing = HorizontalFacingOption::fromFacing($player->getHorizontalFacing());
|
||||
}
|
||||
|
||||
$next = $this->getSide($this->getOtherHalfSide());
|
||||
if($next->canBeReplaced() && $this->canBeSupportedAt($next)){
|
||||
|
@ -26,6 +26,7 @@ namespace pocketmine\block;
|
||||
use pocketmine\block\tile\Bell as TileBell;
|
||||
use pocketmine\block\utils\BellAttachmentType;
|
||||
use pocketmine\block\utils\HorizontalFacing;
|
||||
use pocketmine\block\utils\HorizontalFacingOption;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
@ -46,32 +47,33 @@ final class Bell extends Transparent implements HorizontalFacing{
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->enum($this->attachmentType);
|
||||
$w->horizontalFacing($this->facing);
|
||||
$w->enum($this->facing);
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
$realFacing = $this->facing->toFacing();
|
||||
if($this->attachmentType === BellAttachmentType::FLOOR){
|
||||
return [
|
||||
AxisAlignedBB::one()->squash(Facing::axis($this->facing), 1 / 4)->trim(Facing::UP, 3 / 16)
|
||||
AxisAlignedBB::one()->squashedCopy(Facing::axis($realFacing), 1 / 4)->trimmedCopy(Facing::UP, 3 / 16)
|
||||
];
|
||||
}
|
||||
if($this->attachmentType === BellAttachmentType::CEILING){
|
||||
return [
|
||||
AxisAlignedBB::one()->contract(1 / 4, 0, 1 / 4)->trim(Facing::DOWN, 1 / 4)
|
||||
AxisAlignedBB::one()->contractedCopy(1 / 4, 0, 1 / 4)->trimmedCopy(Facing::DOWN, 1 / 4)
|
||||
];
|
||||
}
|
||||
|
||||
$box = AxisAlignedBB::one()
|
||||
->squash(Facing::axis(Facing::rotateY($this->facing, true)), 1 / 4)
|
||||
->trim(Facing::UP, 1 / 16)
|
||||
->trim(Facing::DOWN, 1 / 4);
|
||||
->squashedCopy(Facing::axis(Facing::rotateY($realFacing, true)), 1 / 4)
|
||||
->trimmedCopy(Facing::UP, 1 / 16)
|
||||
->trimmedCopy(Facing::DOWN, 1 / 4);
|
||||
|
||||
return [
|
||||
$this->attachmentType === BellAttachmentType::ONE_WALL ? $box->trim($this->facing, 3 / 16) : $box
|
||||
$this->attachmentType === BellAttachmentType::ONE_WALL ? $box->trimmedCopy($realFacing, 3 / 16) : $box
|
||||
];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
@ -83,23 +85,23 @@ final class Bell extends Transparent implements HorizontalFacing{
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function canBeSupportedAt(Block $block, int $face) : bool{
|
||||
private function canBeSupportedAt(Block $block, Facing $face) : bool{
|
||||
return $block->getAdjacentSupportType($face) !== SupportType::NONE;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$this->canBeSupportedAt($blockReplace, Facing::opposite($face))){
|
||||
return false;
|
||||
}
|
||||
if($face === Facing::UP){
|
||||
if($player !== null){
|
||||
$this->setFacing(Facing::opposite($player->getHorizontalFacing()));
|
||||
$this->setFacing(HorizontalFacingOption::fromFacing(Facing::opposite($player->getHorizontalFacing())));
|
||||
}
|
||||
$this->setAttachmentType(BellAttachmentType::FLOOR);
|
||||
}elseif($face === Facing::DOWN){
|
||||
$this->setAttachmentType(BellAttachmentType::CEILING);
|
||||
}else{
|
||||
$this->setFacing($face);
|
||||
$this->setFacing(HorizontalFacingOption::fromFacing($face));
|
||||
$this->setAttachmentType(
|
||||
$this->canBeSupportedAt($blockReplace, $face) ?
|
||||
BellAttachmentType::TWO_WALLS :
|
||||
@ -113,8 +115,8 @@ final class Bell extends Transparent implements HorizontalFacing{
|
||||
foreach(match($this->attachmentType){
|
||||
BellAttachmentType::CEILING => [Facing::UP],
|
||||
BellAttachmentType::FLOOR => [Facing::DOWN],
|
||||
BellAttachmentType::ONE_WALL => [Facing::opposite($this->facing)],
|
||||
BellAttachmentType::TWO_WALLS => [$this->facing, Facing::opposite($this->facing)]
|
||||
BellAttachmentType::ONE_WALL => [Facing::opposite($this->facing->toFacing())],
|
||||
BellAttachmentType::TWO_WALLS => [$this->facing->toFacing(), Facing::opposite($this->facing->toFacing())]
|
||||
} as $supportBlockDirection){
|
||||
if(!$this->canBeSupportedAt($this, $supportBlockDirection)){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
@ -123,7 +125,7 @@ final class Bell extends Transparent implements HorizontalFacing{
|
||||
}
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($player !== null){
|
||||
$faceHit = Facing::opposite($player->getHorizontalFacing());
|
||||
if($this->isValidFaceToRing($faceHit)){
|
||||
@ -142,7 +144,7 @@ final class Bell extends Transparent implements HorizontalFacing{
|
||||
}
|
||||
}
|
||||
|
||||
public function ring(int $faceHit) : void{
|
||||
public function ring(Facing $faceHit) : void{
|
||||
$world = $this->position->getWorld();
|
||||
$world->addSound($this->position, new BellRingSound());
|
||||
$tile = $world->getTile($this->position);
|
||||
@ -155,11 +157,11 @@ final class Bell extends Transparent implements HorizontalFacing{
|
||||
return [$this->asItem()];
|
||||
}
|
||||
|
||||
private function isValidFaceToRing(int $faceHit) : bool{
|
||||
private function isValidFaceToRing(Facing $faceHit) : bool{
|
||||
return match($this->attachmentType){
|
||||
BellAttachmentType::CEILING => true,
|
||||
BellAttachmentType::FLOOR => Facing::axis($faceHit) === Facing::axis($this->facing),
|
||||
BellAttachmentType::ONE_WALL, BellAttachmentType::TWO_WALLS => $faceHit === Facing::rotateY($this->facing, false) || $faceHit === Facing::rotateY($this->facing, true),
|
||||
BellAttachmentType::FLOOR => Facing::axis($faceHit) === Facing::axis($this->facing->toFacing()),
|
||||
BellAttachmentType::ONE_WALL, BellAttachmentType::TWO_WALLS => $faceHit === Facing::rotateY($this->facing->toFacing(), false) || $faceHit === Facing::rotateY($this->facing->toFacing(), true),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -80,8 +80,8 @@ class BigDripleafHead extends BaseBigDripleaf{
|
||||
if(!$entity instanceof Projectile && $this->leafState === DripleafState::STABLE){
|
||||
//the entity must be standing on top of the leaf - do not collapse if the entity is standing underneath
|
||||
$intersection = AxisAlignedBB::one()
|
||||
->offset($this->position->x, $this->position->y, $this->position->z)
|
||||
->trim(Facing::DOWN, 1 - $this->getLeafTopOffset());
|
||||
->offsetCopy($this->position->x, $this->position->y, $this->position->z)
|
||||
->trimmedCopy(Facing::DOWN, 1 - $this->getLeafTopOffset());
|
||||
if($entity->getBoundingBox()->intersectsWith($intersection)){
|
||||
$this->setTiltAndScheduleTick(DripleafState::UNSTABLE);
|
||||
return false;
|
||||
@ -116,8 +116,8 @@ class BigDripleafHead extends BaseBigDripleaf{
|
||||
if($this->leafState !== DripleafState::FULL_TILT){
|
||||
return [
|
||||
AxisAlignedBB::one()
|
||||
->trim(Facing::DOWN, 11 / 16)
|
||||
->trim(Facing::UP, $this->getLeafTopOffset())
|
||||
->trimmedCopy(Facing::DOWN, 11 / 16)
|
||||
->trimmedCopy(Facing::UP, $this->getLeafTopOffset())
|
||||
];
|
||||
}
|
||||
return [];
|
||||
|
@ -424,7 +424,7 @@ class Block{
|
||||
* Returns whether this block can replace the given block in the given placement conditions.
|
||||
* This is used to allow slabs of the same type to combine into double slabs.
|
||||
*/
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, Facing $face, bool $isClickedBlock) : bool{
|
||||
return $blockReplace->canBeReplaced();
|
||||
}
|
||||
|
||||
@ -436,13 +436,13 @@ class Block{
|
||||
* @param Item $item Item used to place the block
|
||||
* @param Block $blockReplace Block expected to be replaced
|
||||
* @param Block $blockClicked Block that was clicked using the item
|
||||
* @param int $face Face of the clicked block which was clicked
|
||||
* @param Facing $face Face of the clicked block which was clicked
|
||||
* @param Vector3 $clickVector Exact position inside the clicked block where the click occurred, relative to the block's position
|
||||
* @param Player|null $player Player who placed the block, or null if it was not a player
|
||||
*
|
||||
* @return bool whether the placement should go ahead
|
||||
*/
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$tx->addBlock($blockReplace->position, $this);
|
||||
return true;
|
||||
}
|
||||
@ -524,7 +524,7 @@ class Block{
|
||||
* @param Vector3 $clickVector Exact position where the click occurred, relative to the block's integer position
|
||||
* @param Item[] &$returnedItems Items to be added to the target's inventory (or dropped, if the inventory is full)
|
||||
*/
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -533,7 +533,7 @@ class Block{
|
||||
*
|
||||
* @return bool if an action took place, prevents starting to break the block if true.
|
||||
*/
|
||||
public function onAttack(Item $item, int $face, ?Player $player = null) : bool{
|
||||
public function onAttack(Item $item, Facing $face, ?Player $player = null) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -770,10 +770,10 @@ class Block{
|
||||
*
|
||||
* @return Block
|
||||
*/
|
||||
public function getSide(int $side, int $step = 1){
|
||||
public function getSide(Facing $side, int $step = 1){
|
||||
$position = $this->position;
|
||||
if($position->isValid()){
|
||||
[$dx, $dy, $dz] = Facing::OFFSET[$side] ?? [0, 0, 0];
|
||||
[$dx, $dy, $dz] = Facing::OFFSET[$side->value] ?? [0, 0, 0];
|
||||
return $position->getWorld()->getBlockAt(
|
||||
$position->x + ($dx * $step),
|
||||
$position->y + ($dy * $step),
|
||||
@ -793,7 +793,7 @@ class Block{
|
||||
public function getHorizontalSides() : \Generator{
|
||||
$world = $this->position->getWorld();
|
||||
foreach(Facing::HORIZONTAL as $facing){
|
||||
[$dx, $dy, $dz] = Facing::OFFSET[$facing];
|
||||
[$dx, $dy, $dz] = Facing::OFFSET[$facing->value];
|
||||
//TODO: yield Facing as the key?
|
||||
yield $world->getBlockAt(
|
||||
$this->position->x + $dx,
|
||||
@ -914,11 +914,12 @@ class Block{
|
||||
*/
|
||||
final public function getCollisionBoxes() : array{
|
||||
if($this->collisionBoxes === null){
|
||||
$this->collisionBoxes = $this->recalculateCollisionBoxes();
|
||||
$collisionBoxes = $this->recalculateCollisionBoxes();
|
||||
$extraOffset = $this->getModelPositionOffset();
|
||||
$offset = $extraOffset !== null ? $this->position->addVector($extraOffset) : $this->position;
|
||||
foreach($this->collisionBoxes as $bb){
|
||||
$bb->offset($offset->x, $offset->y, $offset->z);
|
||||
$this->collisionBoxes = [];
|
||||
foreach($collisionBoxes as $bb){
|
||||
$this->collisionBoxes[] = $bb->offsetCopy($offset->x, $offset->y, $offset->z);
|
||||
}
|
||||
}
|
||||
|
||||
@ -945,11 +946,11 @@ class Block{
|
||||
* Returns the type of support that the block can provide on the given face. This is used to determine whether
|
||||
* blocks placed on the given face can be supported by this block.
|
||||
*/
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::FULL;
|
||||
}
|
||||
|
||||
protected function getAdjacentSupportType(int $facing) : SupportType{
|
||||
protected function getAdjacentSupportType(Facing $facing) : SupportType{
|
||||
return $this->getSide($facing)->getSupportType(Facing::opposite($facing));
|
||||
}
|
||||
|
||||
|
@ -23,20 +23,24 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\inventory\window\BrewingStandInventoryWindow;
|
||||
use pocketmine\block\tile\BrewingStand as TileBrewingStand;
|
||||
use pocketmine\block\utils\BrewingStandSlot;
|
||||
use pocketmine\block\utils\Container;
|
||||
use pocketmine\block\utils\ContainerTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\inventory\Inventory;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\Position;
|
||||
use function array_key_exists;
|
||||
use function spl_object_id;
|
||||
|
||||
class BrewingStand extends Transparent{
|
||||
class BrewingStand extends Transparent implements Container{
|
||||
use ContainerTrait;
|
||||
|
||||
/**
|
||||
* @var BrewingStandSlot[]
|
||||
@ -51,17 +55,17 @@ class BrewingStand extends Transparent{
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [
|
||||
//bottom slab part - in PC this is also inset on X/Z by 1/16, but Bedrock sucks
|
||||
AxisAlignedBB::one()->trim(Facing::UP, 7 / 8),
|
||||
AxisAlignedBB::one()->trimmedCopy(Facing::UP, 7 / 8),
|
||||
|
||||
//center post
|
||||
AxisAlignedBB::one()
|
||||
->squash(Axis::X, 7 / 16)
|
||||
->squash(Axis::Z, 7 / 16)
|
||||
->trim(Facing::UP, 1 / 8)
|
||||
->squashedCopy(Axis::X, 7 / 16)
|
||||
->squashedCopy(Axis::Z, 7 / 16)
|
||||
->trimmedCopy(Facing::UP, 1 / 8)
|
||||
];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
@ -95,15 +99,8 @@ class BrewingStand extends Transparent{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($player instanceof Player){
|
||||
$stand = $this->position->getWorld()->getTile($this->position);
|
||||
if($stand instanceof TileBrewingStand && $stand->canOpenWith($item->getCustomName())){
|
||||
$player->setCurrentWindow($stand->getInventory());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
protected function newMenu(Player $player, Inventory $inventory, Position $position) : BrewingStandInventoryWindow{
|
||||
return new BrewingStandInventoryWindow($player, $inventory, $position);
|
||||
}
|
||||
|
||||
public function onScheduledUpdate() : void{
|
||||
|
@ -40,7 +40,7 @@ abstract class Button extends Flowable implements AnyFacing{
|
||||
protected bool $pressed = false;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->facing($this->facing);
|
||||
$w->enum($this->facing);
|
||||
$w->bool($this->pressed);
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ abstract class Button extends Flowable implements AnyFacing{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($this->canBeSupportedAt($blockReplace, $face)){
|
||||
$this->facing = $face;
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
@ -62,7 +62,7 @@ abstract class Button extends Flowable implements AnyFacing{
|
||||
|
||||
abstract protected function getActivationTime() : int;
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if(!$this->pressed){
|
||||
$this->pressed = true;
|
||||
$world = $this->position->getWorld();
|
||||
@ -89,7 +89,7 @@ abstract class Button extends Flowable implements AnyFacing{
|
||||
}
|
||||
}
|
||||
|
||||
private function canBeSupportedAt(Block $block, int $face) : bool{
|
||||
private function canBeSupportedAt(Block $block, Facing $face) : bool{
|
||||
return $block->getAdjacentSupportType(Facing::opposite($face))->hasCenterSupport();
|
||||
}
|
||||
}
|
||||
|
@ -46,10 +46,10 @@ class Cactus extends Transparent implements Ageable{
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
$shrinkSize = 1 / 16;
|
||||
return [AxisAlignedBB::one()->contract($shrinkSize, 0, $shrinkSize)->trim(Facing::UP, $shrinkSize)];
|
||||
return [AxisAlignedBB::one()->contractedCopy($shrinkSize, 0, $shrinkSize)->trimmedCopy(Facing::UP, $shrinkSize)];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
|
@ -43,9 +43,9 @@ class Cake extends BaseCake{
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [
|
||||
AxisAlignedBB::one()
|
||||
->contract(1 / 16, 0, 1 / 16)
|
||||
->trim(Facing::UP, 0.5)
|
||||
->trim(Facing::WEST, $this->bites / 8)
|
||||
->contractedCopy(1 / 16, 0, 1 / 16)
|
||||
->trimmedCopy(Facing::UP, 0.5)
|
||||
->trimmedCopy(Facing::WEST, $this->bites / 8)
|
||||
];
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ class Cake extends BaseCake{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($this->bites === 0 && $item instanceof ItemBlock){
|
||||
$block = $item->getBlock();
|
||||
$resultBlock = null;
|
||||
|
@ -40,8 +40,8 @@ class CakeWithCandle extends BaseCake implements Lightable{
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [
|
||||
AxisAlignedBB::one()
|
||||
->contract(1 / 16, 0, 1 / 16)
|
||||
->trim(Facing::UP, 0.5) //TODO: not sure if the candle affects height
|
||||
->contractedCopy(1 / 16, 0, 1 / 16)
|
||||
->trimmedCopy(Facing::UP, 0.5) //TODO: not sure if the candle affects height
|
||||
];
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ class CakeWithCandle extends BaseCake implements Lightable{
|
||||
return VanillaBlocks::CANDLE();
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($this->lit && $face !== Facing::UP){
|
||||
return true;
|
||||
}
|
||||
|
@ -23,9 +23,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\inventory\CampfireInventory;
|
||||
use pocketmine\block\tile\Campfire as TileCampfire;
|
||||
use pocketmine\block\utils\HorizontalFacing;
|
||||
use pocketmine\block\utils\HorizontalFacingOption;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\Lightable;
|
||||
use pocketmine\block\utils\LightableTrait;
|
||||
@ -40,6 +40,7 @@ use pocketmine\entity\projectile\SplashPotion;
|
||||
use pocketmine\event\block\CampfireCookEvent;
|
||||
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\inventory\Inventory;
|
||||
use pocketmine\item\Durable;
|
||||
use pocketmine\item\enchantment\VanillaEnchantments;
|
||||
use pocketmine\item\Item;
|
||||
@ -75,7 +76,7 @@ class Campfire extends Transparent implements Lightable, HorizontalFacing{
|
||||
* @deprecated This was added by mistake. It can't be relied on as the inventory won't be initialized if this block
|
||||
* has never been set in the world.
|
||||
*/
|
||||
protected CampfireInventory $inventory;
|
||||
protected ?Inventory $inventory = null;
|
||||
|
||||
/**
|
||||
* @var int[] slot => ticks
|
||||
@ -95,7 +96,8 @@ class Campfire extends Transparent implements Lightable, HorizontalFacing{
|
||||
$this->inventory = $tile->getInventory();
|
||||
$this->cookingTimes = $tile->getCookingTimes();
|
||||
}else{
|
||||
$this->inventory = new CampfireInventory($this->position);
|
||||
$this->inventory = null;
|
||||
$this->cookingTimes = [];
|
||||
}
|
||||
|
||||
return $this;
|
||||
@ -127,19 +129,19 @@ class Campfire extends Transparent implements Lightable, HorizontalFacing{
|
||||
];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->trim(Facing::UP, 9 / 16)];
|
||||
return [AxisAlignedBB::one()->trimmedCopy(Facing::UP, 9 / 16)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This was added by mistake. It can't be relied on as the inventory won't be initialized if this block
|
||||
* has never been set in the world.
|
||||
*/
|
||||
public function getInventory() : CampfireInventory{
|
||||
public function getInventory() : ?Inventory{
|
||||
return $this->inventory;
|
||||
}
|
||||
|
||||
@ -171,18 +173,18 @@ class Campfire extends Transparent implements Lightable, HorizontalFacing{
|
||||
return $this->cookingTimes[$slot] ?? 0;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($this->getSide(Facing::DOWN) instanceof Campfire){
|
||||
return false;
|
||||
}
|
||||
if($player !== null){
|
||||
$this->facing = $player->getHorizontalFacing();
|
||||
$this->facing = HorizontalFacingOption::fromFacing($player->getHorizontalFacing());
|
||||
}
|
||||
$this->lit = true;
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if(!$this->lit){
|
||||
if($item->getTypeId() === ItemTypeIds::FIRE_CHARGE){
|
||||
$item->pop();
|
||||
@ -202,10 +204,11 @@ class Campfire extends Transparent implements Lightable, HorizontalFacing{
|
||||
return true;
|
||||
}
|
||||
|
||||
if($this->position->getWorld()->getServer()->getCraftingManager()->getFurnaceRecipeManager($this->getFurnaceType())->match($item) !== null){
|
||||
$inventory = $this->inventory;
|
||||
if($inventory !== null && $this->position->getWorld()->getServer()->getCraftingManager()->getFurnaceRecipeManager($this->getFurnaceType())->match($item) !== null){
|
||||
$ingredient = clone $item;
|
||||
$ingredient->setCount(1);
|
||||
if(count($this->inventory->addItem($ingredient)) === 0){
|
||||
if(count($inventory->addItem($ingredient)) === 0){
|
||||
$item->pop();
|
||||
$this->position->getWorld()->addSound($this->position, new ItemFrameAddItemSound());
|
||||
return true;
|
||||
@ -240,8 +243,8 @@ class Campfire extends Transparent implements Lightable, HorizontalFacing{
|
||||
}
|
||||
|
||||
public function onScheduledUpdate() : void{
|
||||
if($this->lit){
|
||||
$items = $this->inventory->getContents();
|
||||
if($this->lit && ($inventory = $this->inventory) !== null){
|
||||
$items = $inventory->getContents();
|
||||
$furnaceType = $this->getFurnaceType();
|
||||
$maxCookDuration = $furnaceType->getCookDurationTicks();
|
||||
foreach($items as $slot => $item){
|
||||
@ -259,7 +262,7 @@ class Campfire extends Transparent implements Lightable, HorizontalFacing{
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->inventory->setItem($slot, VanillaItems::AIR());
|
||||
$inventory->setItem($slot, VanillaItems::AIR());
|
||||
$this->setCookingTime($slot, 0);
|
||||
$this->position->getWorld()->dropItem($this->position->add(0.5, 1, 0.5), $ev->getResult());
|
||||
}
|
||||
|
@ -71,27 +71,27 @@ class Candle extends Transparent implements Lightable{
|
||||
return [
|
||||
(match($this->count){
|
||||
1 => AxisAlignedBB::one()
|
||||
->squash(Axis::X, 7 / 16)
|
||||
->squash(Axis::Z, 7 / 16),
|
||||
->squashedCopy(Axis::X, 7 / 16)
|
||||
->squashedCopy(Axis::Z, 7 / 16),
|
||||
2 => AxisAlignedBB::one()
|
||||
->squash(Axis::X, 5 / 16)
|
||||
->trim(Facing::NORTH, 7 / 16) //0.3 thick on the Z axis
|
||||
->trim(Facing::SOUTH, 6 / 16),
|
||||
->squashedCopy(Axis::X, 5 / 16)
|
||||
->trimmedCopy(Facing::NORTH, 7 / 16) //0.3 thick on the Z axis
|
||||
->trimmedCopy(Facing::SOUTH, 6 / 16),
|
||||
3 => AxisAlignedBB::one()
|
||||
->trim(Facing::WEST, 5 / 16)
|
||||
->trim(Facing::EAST, 6 / 16)
|
||||
->trim(Facing::NORTH, 6 / 16)
|
||||
->trim(Facing::SOUTH, 5 / 16),
|
||||
->trimmedCopy(Facing::WEST, 5 / 16)
|
||||
->trimmedCopy(Facing::EAST, 6 / 16)
|
||||
->trimmedCopy(Facing::NORTH, 6 / 16)
|
||||
->trimmedCopy(Facing::SOUTH, 5 / 16),
|
||||
4 => AxisAlignedBB::one()
|
||||
->squash(Axis::X, 5 / 16)
|
||||
->trim(Facing::NORTH, 5 / 16)
|
||||
->trim(Facing::SOUTH, 6 / 16),
|
||||
->squashedCopy(Axis::X, 5 / 16)
|
||||
->trimmedCopy(Facing::NORTH, 5 / 16)
|
||||
->trimmedCopy(Facing::SOUTH, 6 / 16),
|
||||
default => throw new AssumptionFailedError("Unreachable")
|
||||
})->trim(Facing::UP, 10 / 16)
|
||||
})->trimmedCopy(Facing::UP, 10 / 16)
|
||||
];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
@ -99,12 +99,12 @@ class Candle extends Transparent implements Lightable{
|
||||
return $block instanceof Candle && $block->hasSameTypeId($this) ? $block : null;
|
||||
}
|
||||
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, Facing $face, bool $isClickedBlock) : bool{
|
||||
$candle = $this->getCandleIfCompatibleType($blockReplace);
|
||||
return $candle !== null ? $candle->count < self::MAX_COUNT : parent::canBePlacedAt($blockReplace, $clickVector, $face, $isClickedBlock);
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$blockReplace->getAdjacentSupportType(Facing::DOWN)->hasCenterSupport()){
|
||||
return false;
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ class Carpet extends Flowable implements Colored{
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->trim(Facing::UP, 15 / 16)];
|
||||
return [AxisAlignedBB::one()->trimmedCopy(Facing::UP, 15 / 16)];
|
||||
}
|
||||
|
||||
private function canBeSupportedAt(Block $block) : bool{
|
||||
|
@ -23,19 +23,17 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\inventory\CartographyTableInventory;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\block\inventory\window\CartographyTableInventoryWindow;
|
||||
use pocketmine\block\utils\MenuAccessor;
|
||||
use pocketmine\block\utils\MenuAccessorTrait;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
final class CartographyTable extends Opaque{
|
||||
final class CartographyTable extends Opaque implements MenuAccessor{
|
||||
use MenuAccessorTrait;
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($player !== null){
|
||||
$player->setCurrentWindow(new CartographyTableInventory($this->position));
|
||||
}
|
||||
|
||||
return true;
|
||||
protected function newMenu(Player $player, Position $position) : CartographyTableInventoryWindow{
|
||||
return new CartographyTableInventoryWindow($player, $position);
|
||||
}
|
||||
|
||||
public function getFuelTime() : int{
|
||||
|
@ -51,16 +51,16 @@ final class Cauldron extends Transparent{
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
$result = [
|
||||
AxisAlignedBB::one()->trim(Facing::UP, 11 / 16) //bottom of the cauldron
|
||||
AxisAlignedBB::one()->trimmedCopy(Facing::UP, 11 / 16) //bottom of the cauldron
|
||||
];
|
||||
|
||||
foreach(Facing::HORIZONTAL as $f){ //add the frame parts around the bowl
|
||||
$result[] = AxisAlignedBB::one()->trim($f, 14 / 16);
|
||||
$result[] = AxisAlignedBB::one()->trimmedCopy($f, 14 / 16);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return $facing === Facing::UP ? SupportType::EDGE : SupportType::NONE;
|
||||
}
|
||||
|
||||
@ -75,7 +75,7 @@ final class Cauldron extends Transparent{
|
||||
$returnedItems[] = $returnedItem;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item->getTypeId() === ItemTypeIds::WATER_BUCKET){
|
||||
$this->fill(FillableCauldron::MAX_FILL_LEVEL, VanillaBlocks::WATER_CAULDRON(), $item, VanillaItems::BUCKET(), $returnedItems);
|
||||
}elseif($item->getTypeId() === ItemTypeIds::LAVA_BUCKET){
|
||||
|
@ -84,12 +84,12 @@ class CaveVines extends Flowable implements Ageable{
|
||||
return $supportBlock->getSupportType(Facing::DOWN) === SupportType::FULL || $supportBlock->hasSameTypeId($this);
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$this->age = mt_rand(0, self::MAX_AGE);
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($this->berries){
|
||||
$this->position->getWorld()->dropItem($this->position, $this->asItem());
|
||||
$this->position->getWorld()->addSound($this->position, new GlowBerriesPickSound());
|
||||
@ -159,7 +159,7 @@ class CaveVines extends Flowable implements Ageable{
|
||||
return VanillaItems::GLOW_BERRIES();
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
}
|
||||
|
@ -36,12 +36,12 @@ final class CeilingCenterHangingSign extends BaseSign implements SignLikeRotatio
|
||||
use SignLikeRotationTrait;
|
||||
use StaticSupportTrait;
|
||||
|
||||
protected function getSupportingFace() : int{
|
||||
protected function getSupportingFace() : Facing{
|
||||
return Facing::UP;
|
||||
}
|
||||
|
||||
//TODO: duplicated code :(
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($face !== Facing::DOWN){
|
||||
return false;
|
||||
}
|
||||
@ -58,4 +58,8 @@ final class CeilingCenterHangingSign extends BaseSign implements SignLikeRotatio
|
||||
$supportBlock->getSupportType(Facing::DOWN)->hasCenterSupport() ||
|
||||
$supportBlock->hasTypeTag(BlockTypeTags::HANGING_SIGN);
|
||||
}
|
||||
|
||||
protected function getFacingDegrees() : float{
|
||||
return $this->rotation * 22.5;
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\HorizontalFacing;
|
||||
use pocketmine\block\utils\HorizontalFacingOption;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\item\Item;
|
||||
@ -35,16 +36,16 @@ use pocketmine\world\BlockTransaction;
|
||||
final class CeilingEdgesHangingSign extends BaseSign implements HorizontalFacing{
|
||||
use HorizontalFacingTrait;
|
||||
|
||||
protected function getSupportingFace() : int{
|
||||
protected function getSupportingFace() : Facing{
|
||||
return Facing::UP;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($face !== Facing::DOWN){
|
||||
return false;
|
||||
}
|
||||
if($player !== null){
|
||||
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
||||
$this->facing = HorizontalFacingOption::fromFacing(Facing::opposite($player->getHorizontalFacing()));
|
||||
}
|
||||
if(!$this->canBeSupportedAt($blockReplace)){
|
||||
return false;
|
||||
@ -63,6 +64,15 @@ final class CeilingEdgesHangingSign extends BaseSign implements HorizontalFacing
|
||||
$supportBlock = $block->getSide(Facing::UP);
|
||||
return
|
||||
$supportBlock->getSupportType(Facing::DOWN) === SupportType::FULL ||
|
||||
(($supportBlock instanceof WallHangingSign || $supportBlock instanceof CeilingEdgesHangingSign) && Facing::axis($supportBlock->getFacing()) === Facing::axis($this->facing));
|
||||
(($supportBlock instanceof WallHangingSign || $supportBlock instanceof CeilingEdgesHangingSign) && Facing::axis($supportBlock->getFacing()->toFacing()) === Facing::axis($this->facing->toFacing()));
|
||||
}
|
||||
|
||||
protected function getFacingDegrees() : float{
|
||||
return match($this->facing){
|
||||
HorizontalFacingOption::SOUTH => 0,
|
||||
HorizontalFacingOption::WEST => 90,
|
||||
HorizontalFacingOption::NORTH => 180,
|
||||
HorizontalFacingOption::EAST => 270,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ use pocketmine\math\Facing;
|
||||
final class Chain extends Transparent implements PillarRotation{
|
||||
use PillarRotationTrait;
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return $this->axis === Axis::Y && Facing::axis($facing) === Axis::Y ? SupportType::CENTER : SupportType::NONE;
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ final class Chain extends Transparent implements PillarRotation{
|
||||
$bb = AxisAlignedBB::one();
|
||||
foreach([Axis::Y, Axis::Z, Axis::X] as $axis){
|
||||
if($axis !== $this->axis){
|
||||
$bb->squash($axis, 13 / 32);
|
||||
$bb = $bb->squashedCopy($axis, 13 / 32);
|
||||
}
|
||||
}
|
||||
return [$bb];
|
||||
|
@ -26,13 +26,14 @@ namespace pocketmine\block;
|
||||
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
|
||||
use pocketmine\block\utils\HorizontalFacing;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
final class ChemistryTable extends Opaque implements HorizontalFacing{
|
||||
use FacesOppositePlacingPlayerTrait;
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
//TODO
|
||||
return false;
|
||||
}
|
||||
|
@ -23,74 +23,203 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\inventory\window\BlockInventoryWindow;
|
||||
use pocketmine\block\inventory\window\DoubleChestInventoryWindow;
|
||||
use pocketmine\block\tile\Chest as TileChest;
|
||||
use pocketmine\block\utils\AnimatedContainerLike;
|
||||
use pocketmine\block\utils\AnimatedContainerLikeTrait;
|
||||
use pocketmine\block\utils\ChestPairHalf;
|
||||
use pocketmine\block\utils\Container;
|
||||
use pocketmine\block\utils\ContainerTrait;
|
||||
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
|
||||
use pocketmine\block\utils\HorizontalFacing;
|
||||
use pocketmine\block\utils\HorizontalFacingOption;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\event\block\ChestPairEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\inventory\CombinedInventoryProxy;
|
||||
use pocketmine\inventory\Inventory;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\protocol\BlockEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\BlockPosition;
|
||||
use pocketmine\player\InventoryWindow;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\Position;
|
||||
use pocketmine\world\sound\ChestCloseSound;
|
||||
use pocketmine\world\sound\ChestOpenSound;
|
||||
use pocketmine\world\sound\Sound;
|
||||
use function assert;
|
||||
|
||||
class Chest extends Transparent implements HorizontalFacing{
|
||||
class Chest extends Transparent implements AnimatedContainerLike, Container, HorizontalFacing{
|
||||
use AnimatedContainerLikeTrait;
|
||||
use ContainerTrait;
|
||||
use FacesOppositePlacingPlayerTrait;
|
||||
|
||||
protected ?ChestPairHalf $pairHalf = null;
|
||||
|
||||
public function getPairHalf() : ?ChestPairHalf{ return $this->pairHalf; }
|
||||
|
||||
public function setPairHalf(?ChestPairHalf $pairHalf) : self{
|
||||
$this->pairHalf = $pairHalf;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function readStateFromWorld() : Block{
|
||||
parent::readStateFromWorld();
|
||||
$tile = $this->position->getWorld()->getTile($this->position);
|
||||
|
||||
$this->pairHalf = null;
|
||||
if($tile instanceof TileChest && ($pairXZ = $tile->getPairXZ()) !== null){
|
||||
[$pairX, $pairZ] = $pairXZ;
|
||||
foreach(ChestPairHalf::cases() as $pairSide){
|
||||
$pairDirection = $pairSide->getOtherHalfSide($this->facing);
|
||||
$pairPosition = $this->position->getSide($pairDirection);
|
||||
if($pairPosition->getFloorX() === $pairX && $pairPosition->getFloorZ() === $pairZ){
|
||||
$this->pairHalf = $pairSide;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function writeStateToWorld() : void{
|
||||
parent::writeStateToWorld();
|
||||
$tile = $this->position->getWorld()->getTile($this->position);
|
||||
assert($tile instanceof TileChest);
|
||||
|
||||
//TODO: this should probably use relative coordinates instead of absolute, for portability
|
||||
if($this->pairHalf !== null){
|
||||
$pairDirection = $this->pairHalf->getOtherHalfSide($this->facing);
|
||||
$pairPosition = $this->position->getSide($pairDirection);
|
||||
$pairXZ = [$pairPosition->getFloorX(), $pairPosition->getFloorZ()];
|
||||
}else{
|
||||
$pairXZ = null;
|
||||
}
|
||||
$tile->setPairXZ($pairXZ);
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
//these are slightly bigger than in PC
|
||||
return [AxisAlignedBB::one()->contract(0.025, 0, 0.025)->trim(Facing::UP, 0.05)];
|
||||
$facing = $this->facing->toFacing();
|
||||
$box = AxisAlignedBB::one()
|
||||
->squashedCopy(Facing::axis($facing), 0.025)
|
||||
->trimmedCopy(Facing::UP, 0.05);
|
||||
$pairSide = $this->pairHalf?->getOtherHalfSide($this->facing);
|
||||
return [$pairSide !== null ?
|
||||
$box->trimmedCopy(Facing::opposite($pairSide), 0.025) :
|
||||
$box->squashedCopy(Facing::axis(Facing::rotateY($facing, true)), 0.025)
|
||||
];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
private function getPossiblePair(ChestPairHalf $pairSide) : ?Chest{
|
||||
$pair = $this->getSide($pairSide->getOtherHalfSide($this->facing));
|
||||
return $pair->hasSameTypeId($this) && $pair instanceof Chest && $pair->getFacing() === $this->facing ? $pair : null;
|
||||
}
|
||||
|
||||
public function getOtherHalf() : ?Chest{
|
||||
return $this->pairHalf !== null && ($pair = $this->getPossiblePair($this->pairHalf)) !== null && $pair->pairHalf === $this->pairHalf->opposite() ? $pair : null;
|
||||
}
|
||||
|
||||
public function onPostPlace() : void{
|
||||
//Not sure if this vanilla behaviour is intended, but a chest facing north or west will try to pair on the left
|
||||
//side first, while a chest facing south or east will try the right side first.
|
||||
$order = match($this->facing){
|
||||
HorizontalFacingOption::NORTH, HorizontalFacingOption::WEST => [ChestPairHalf::LEFT, ChestPairHalf::RIGHT],
|
||||
HorizontalFacingOption::SOUTH, HorizontalFacingOption::EAST => [ChestPairHalf::RIGHT, ChestPairHalf::LEFT]
|
||||
};
|
||||
$world = $this->position->getWorld();
|
||||
$tile = $world->getTile($this->position);
|
||||
if($tile instanceof TileChest){
|
||||
foreach([false, true] as $clockwise){
|
||||
$side = Facing::rotateY($this->facing, $clockwise);
|
||||
$c = $this->getSide($side);
|
||||
if($c instanceof Chest && $c->hasSameTypeId($this) && $c->facing === $this->facing){
|
||||
$pair = $world->getTile($c->position);
|
||||
if($pair instanceof TileChest && !$pair->isPaired()){
|
||||
[$left, $right] = $clockwise ? [$c, $this] : [$this, $c];
|
||||
$ev = new ChestPairEvent($left, $right);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled() && $world->getBlock($this->position)->hasSameTypeId($this) && $world->getBlock($c->position)->hasSameTypeId($c)){
|
||||
$pair->pairWith($tile);
|
||||
$tile->pairWith($pair);
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach($order as $pairSide){
|
||||
$possiblePair = $this->getPossiblePair($pairSide);
|
||||
if($possiblePair !== null && $possiblePair->pairHalf === null){
|
||||
[$left, $right] = $pairSide === ChestPairHalf::LEFT ? [$this, $possiblePair] : [$possiblePair, $this];
|
||||
$ev = new ChestPairEvent($left, $right);
|
||||
if(!$ev->isCancelled() && $world->getBlock($this->position)->isSameState($this) && $world->getBlock($possiblePair->position)->isSameState($possiblePair)){
|
||||
$world->setBlock($this->position, $this->setPairHalf($pairSide));
|
||||
$world->setBlock($possiblePair->position, $possiblePair->setPairHalf($pairSide->opposite()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($player instanceof Player){
|
||||
public function onNearbyBlockChange() : void{
|
||||
//TODO: If the pair chunk isn't loaded, a block update of an adjacent block in loaded terrain could cause the
|
||||
//chest to become unpaired. However, this is not unique to chests (think wall connections). Probably we
|
||||
//should defer updates in chunks whose neighbours are not loaded?
|
||||
if($this->pairHalf !== null && $this->getOtherHalf() === null){
|
||||
$this->position->getWorld()->setBlock($this->position, $this->setPairHalf(null));
|
||||
}
|
||||
}
|
||||
|
||||
$chest = $this->position->getWorld()->getTile($this->position);
|
||||
if($chest instanceof TileChest){
|
||||
if(
|
||||
!$this->getSide(Facing::UP)->isTransparent() ||
|
||||
(($pair = $chest->getPair()) !== null && !$pair->getBlock()->getSide(Facing::UP)->isTransparent()) ||
|
||||
!$chest->canOpenWith($item->getCustomName())
|
||||
){
|
||||
return true;
|
||||
}
|
||||
|
||||
$player->setCurrentWindow($chest->getInventory());
|
||||
public function isOpeningObstructed() : bool{
|
||||
foreach([$this, $this->getOtherHalf()] as $chest){
|
||||
if($chest !== null && !$chest->getSide(Facing::UP)->isTransparent()){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
protected function getTile() : ?TileChest{
|
||||
$tile = $this->position->getWorld()->getTile($this->position);
|
||||
return $tile instanceof TileChest ? $tile : null;
|
||||
}
|
||||
|
||||
public function getInventory() : ?Inventory{
|
||||
$thisInventory = $this->getTile()?->getRealInventory();
|
||||
if($thisInventory === null){
|
||||
return null;
|
||||
}
|
||||
$pairInventory = $this->getOtherHalf()?->getTile()?->getRealInventory();
|
||||
if($pairInventory === null){
|
||||
return $thisInventory;
|
||||
}
|
||||
|
||||
[$left, $right] = $this->pairHalf === ChestPairHalf::LEFT ? [$thisInventory, $pairInventory] : [$pairInventory, $thisInventory];
|
||||
return new CombinedInventoryProxy([$left, $right]);
|
||||
}
|
||||
|
||||
protected function newMenu(Player $player, Inventory $inventory, Position $position) : InventoryWindow{
|
||||
$pair = $this->getOtherHalf();
|
||||
if($pair === null){
|
||||
return new BlockInventoryWindow($player, $inventory, $position);
|
||||
}
|
||||
[$left, $right] = $this->pairHalf === ChestPairHalf::LEFT ? [$this, $pair] : [$pair, $this];
|
||||
return new DoubleChestInventoryWindow($player, $inventory, $left->position, $right->position);
|
||||
}
|
||||
|
||||
public function getFuelTime() : int{
|
||||
return 300;
|
||||
}
|
||||
|
||||
protected function getOpenSound() : Sound{
|
||||
return new ChestOpenSound();
|
||||
}
|
||||
|
||||
protected function getCloseSound() : Sound{
|
||||
return new ChestCloseSound();
|
||||
}
|
||||
|
||||
protected function playAnimationVisual(Position $position, bool $isOpen) : void{
|
||||
//event ID is always 1 for a chest
|
||||
//TODO: we probably shouldn't be sending a packet directly here, but it doesn't fit anywhere into existing systems
|
||||
$position->getWorld()->broadcastPacketToViewers($position, BlockEventPacket::create(BlockPosition::fromVector3($position), 1, $isOpen ? 1 : 0));
|
||||
}
|
||||
|
||||
protected function doAnimationEffects(bool $isOpen) : void{
|
||||
$this->playAnimationVisual($this->position, $isOpen);
|
||||
$this->playAnimationSound($this->position, $isOpen);
|
||||
|
||||
$pair = $this->getOtherHalf();
|
||||
if($pair !== null){
|
||||
$this->playAnimationVisual($pair->position, $isOpen);
|
||||
$this->playAnimationSound($pair->position, $isOpen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ class ChiseledBookshelf extends Opaque implements HorizontalFacing{
|
||||
private ?ChiseledBookshelfSlot $lastInteractedSlot = null;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->horizontalFacing($this->facing);
|
||||
$w->enum($this->facing);
|
||||
$w->enumSet($this->slots, ChiseledBookshelfSlot::cases());
|
||||
}
|
||||
|
||||
@ -143,8 +143,8 @@ class ChiseledBookshelf extends Opaque implements HorizontalFacing{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($face !== $this->facing){
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($face !== $this->facing->toFacing()){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -106,9 +106,9 @@ final class ChorusFlower extends Flowable implements Ageable{
|
||||
return [$stemHeight, $endStoneBelow];
|
||||
}
|
||||
|
||||
private function allHorizontalBlocksEmpty(World $world, Vector3 $position, ?int $except) : bool{
|
||||
private function allHorizontalBlocksEmpty(World $world, Vector3 $position, ?Facing $except) : bool{
|
||||
foreach($position->sidesAroundAxis(Axis::Y) as $facing => $sidePosition){
|
||||
if($facing === $except){
|
||||
if($facing === $except?->value){
|
||||
continue;
|
||||
}
|
||||
if($world->getBlock($sidePosition)->getTypeId() !== BlockTypeIds::AIR){
|
||||
@ -149,7 +149,7 @@ final class ChorusFlower extends Flowable implements Ageable{
|
||||
return $this->allHorizontalBlocksEmpty($world, $up, null);
|
||||
}
|
||||
|
||||
private function grow(int $facing, int $ageChange, ?BlockTransaction $tx) : BlockTransaction{
|
||||
private function grow(Facing $facing, int $ageChange, ?BlockTransaction $tx) : BlockTransaction{
|
||||
if($tx === null){
|
||||
$tx = new BlockTransaction($this->position->getWorld());
|
||||
}
|
||||
@ -176,10 +176,10 @@ final class ChorusFlower extends Flowable implements Ageable{
|
||||
$facingVisited = [];
|
||||
for($attempts = 0, $maxAttempts = mt_rand(0, $endStoneBelow ? 4 : 3); $attempts < $maxAttempts; $attempts++){
|
||||
$facing = Facing::HORIZONTAL[array_rand(Facing::HORIZONTAL)];
|
||||
if(isset($facingVisited[$facing])){
|
||||
if(isset($facingVisited[$facing->value])){
|
||||
continue;
|
||||
}
|
||||
$facingVisited[$facing] = true;
|
||||
$facingVisited[$facing->value] = true;
|
||||
|
||||
$sidePosition = $this->position->getSide($facing);
|
||||
if(
|
||||
|
@ -43,8 +43,8 @@ final class ChorusPlant extends Flowable{
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
$bb = AxisAlignedBB::one();
|
||||
foreach(Facing::ALL as $facing){
|
||||
if(!isset($this->connections[$facing])){
|
||||
$bb->trim($facing, 2 / 16);
|
||||
if(!isset($this->connections[$facing->value])){
|
||||
$bb = $bb->trimmedCopy($facing, 2 / 16);
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,9 +62,9 @@ final class ChorusPlant extends Flowable{
|
||||
BlockTypeIds::END_STONE, BlockTypeIds::CHORUS_FLOWER, $this->getTypeId() => true,
|
||||
default => false
|
||||
}){
|
||||
$this->connections[$facing] = true;
|
||||
$this->connections[$facing->value] = true;
|
||||
}else{
|
||||
unset($this->connections[$facing]);
|
||||
unset($this->connections[$facing->value]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,13 +27,13 @@ use pocketmine\block\utils\Ageable;
|
||||
use pocketmine\block\utils\AgeableTrait;
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\HorizontalFacing;
|
||||
use pocketmine\block\utils\HorizontalFacingOption;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\WoodType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
@ -48,18 +48,19 @@ class CocoaBlock extends Flowable implements Ageable, HorizontalFacing{
|
||||
public const MAX_AGE = 2;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->horizontalFacing($this->facing);
|
||||
$w->enum($this->facing);
|
||||
$w->boundedIntAuto(0, self::MAX_AGE, $this->age);
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
$realFacing = $this->facing->toFacing();
|
||||
return [
|
||||
AxisAlignedBB::one()
|
||||
->squash(Facing::axis(Facing::rotateY($this->facing, true)), (6 - $this->age) / 16) //sides
|
||||
->trim(Facing::DOWN, (7 - $this->age * 2) / 16)
|
||||
->trim(Facing::UP, 0.25)
|
||||
->trim(Facing::opposite($this->facing), 1 / 16) //gap between log and pod
|
||||
->trim($this->facing, (11 - $this->age * 2) / 16) //outward face
|
||||
->squashedCopy(Facing::axis(Facing::rotateY($realFacing, true)), (6 - $this->age) / 16) //sides
|
||||
->trimmedCopy(Facing::DOWN, (7 - $this->age * 2) / 16)
|
||||
->trimmedCopy(Facing::UP, 0.25)
|
||||
->trimmedCopy(Facing::opposite($realFacing), 1 / 16) //gap between log and pod
|
||||
->trimmedCopy($realFacing, (11 - $this->age * 2) / 16) //outward face
|
||||
];
|
||||
}
|
||||
|
||||
@ -67,16 +68,16 @@ class CocoaBlock extends Flowable implements Ageable, HorizontalFacing{
|
||||
return $block instanceof Wood && $block->getWoodType() === WoodType::JUNGLE;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(Facing::axis($face) !== Axis::Y && $this->canAttachTo($blockClicked)){
|
||||
$this->facing = $face;
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(($hzFacing = HorizontalFacingOption::tryFromFacing($face)) !== null && $this->canAttachTo($blockClicked)){
|
||||
$this->facing = $hzFacing;
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item instanceof Fertilizer && $this->grow($player)){
|
||||
$item->pop();
|
||||
|
||||
@ -87,7 +88,7 @@ class CocoaBlock extends Flowable implements Ageable, HorizontalFacing{
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(!$this->canAttachTo($this->getSide(Facing::opposite($this->facing)))){
|
||||
if(!$this->canAttachTo($this->getSide(Facing::opposite($this->facing->toFacing())))){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ class CopperDoor extends Door implements CopperMaterial{
|
||||
onInteract as onInteractCopper;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if ($player !== null && $player->isSneaking() && $this->onInteractCopper($item, $face, $clickVector, $player, $returnedItems)) {
|
||||
//copy copper properties to other half
|
||||
$other = $this->getSide($this->top ? Facing::DOWN : Facing::UP);
|
||||
|
@ -26,6 +26,7 @@ namespace pocketmine\block;
|
||||
use pocketmine\block\utils\CopperMaterial;
|
||||
use pocketmine\block\utils\CopperTrait;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
@ -34,7 +35,7 @@ class CopperTrapdoor extends Trapdoor implements CopperMaterial{
|
||||
onInteract as onInteractCopper;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if ($player !== null && $player->isSneaking() && $this->onInteractCopper($item, $face, $clickVector, $player, $returnedItems)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -23,19 +23,17 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\inventory\CraftingTableInventory;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\block\inventory\window\CraftingTableInventoryWindow;
|
||||
use pocketmine\block\utils\MenuAccessor;
|
||||
use pocketmine\block\utils\MenuAccessorTrait;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
class CraftingTable extends Opaque{
|
||||
class CraftingTable extends Opaque implements MenuAccessor{
|
||||
use MenuAccessorTrait;
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($player instanceof Player){
|
||||
$player->setCurrentWindow(new CraftingTableInventory($this->position));
|
||||
}
|
||||
|
||||
return true;
|
||||
protected function newMenu(Player $player, Position $position) : CraftingTableInventoryWindow{
|
||||
return new CraftingTableInventoryWindow($player, $position);
|
||||
}
|
||||
|
||||
public function getFuelTime() : int{
|
||||
|
@ -45,7 +45,7 @@ abstract class Crops extends Flowable implements Ageable{
|
||||
return $block->getSide(Facing::DOWN)->getTypeId() === BlockTypeIds::FARMLAND;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($this->age < self::MAX_AGE && $item instanceof Fertilizer){
|
||||
$block = clone $this;
|
||||
$tempAge = $block->age + mt_rand(2, 5);
|
||||
|
@ -64,14 +64,14 @@ class DaylightSensor extends Transparent implements AnalogRedstoneSignalEmitter{
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->trim(Facing::UP, 10 / 16)];
|
||||
return [AxisAlignedBB::one()->trimmedCopy(Facing::UP, 10 / 16)];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
$this->inverted = !$this->inverted;
|
||||
$this->signalStrength = $this->recalculateSignalStrength();
|
||||
$this->position->getWorld()->setBlock($this->position, $this);
|
||||
|
@ -52,7 +52,7 @@ class Dirt extends Opaque{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
$world = $this->position->getWorld();
|
||||
if($face !== Facing::DOWN && $item instanceof Hoe){
|
||||
$up = $this->getSide(Facing::UP);
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\HorizontalFacing;
|
||||
use pocketmine\block\utils\HorizontalFacingOption;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
@ -43,7 +44,7 @@ class Door extends Transparent implements HorizontalFacing{
|
||||
protected bool $open = false;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->horizontalFacing($this->facing);
|
||||
$w->enum($this->facing);
|
||||
$w->bool($this->top);
|
||||
$w->bool($this->hingeRight);
|
||||
$w->bool($this->open);
|
||||
@ -98,10 +99,10 @@ class Door extends Transparent implements HorizontalFacing{
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
//TODO: doors are 0.1825 blocks thick, instead of 0.1875 like JE (https://bugs.mojang.com/browse/MCPE-19214)
|
||||
return [AxisAlignedBB::one()->trim($this->open ? Facing::rotateY($this->facing, !$this->hingeRight) : $this->facing, 327 / 400)];
|
||||
return [AxisAlignedBB::one()->trimmedCopy($this->open ? Facing::rotateY($this->facing->toFacing(), !$this->hingeRight) : $this->facing->toFacing(), 327 / 400)];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
@ -111,7 +112,7 @@ class Door extends Transparent implements HorizontalFacing{
|
||||
}
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($face === Facing::UP){
|
||||
$blockUp = $this->getSide(Facing::UP);
|
||||
if(!$blockUp->canBeReplaced() || !$this->canBeSupportedAt($blockReplace)){
|
||||
@ -119,11 +120,13 @@ class Door extends Transparent implements HorizontalFacing{
|
||||
}
|
||||
|
||||
if($player !== null){
|
||||
$this->facing = $player->getHorizontalFacing();
|
||||
//TODO: not sure if entities should use HorizontalFacingOption too
|
||||
$this->facing = HorizontalFacingOption::fromFacing($player->getHorizontalFacing());
|
||||
}
|
||||
|
||||
$next = $this->getSide(Facing::rotateY($this->facing, false));
|
||||
$next2 = $this->getSide(Facing::rotateY($this->facing, true));
|
||||
$realFacing = $this->facing->toFacing();
|
||||
$next = $this->getSide(Facing::rotateY($realFacing, false));
|
||||
$next2 = $this->getSide(Facing::rotateY($realFacing, true));
|
||||
|
||||
if($next->hasSameTypeId($this) || (!$next2->isTransparent() && $next->isTransparent())){ //Door hinge
|
||||
$this->hingeRight = true;
|
||||
@ -139,7 +142,7 @@ class Door extends Transparent implements HorizontalFacing{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
$this->open = !$this->open;
|
||||
|
||||
$other = $this->getSide($this->top ? Facing::DOWN : Facing::UP);
|
||||
|
@ -58,10 +58,10 @@ final class DoublePitcherCrop extends DoublePlant implements Ageable{
|
||||
//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
|
||||
->trimmedCopy(Facing::UP, 11 / 16)
|
||||
->squashedCopy(Axis::X, 3 / 16)
|
||||
->squashedCopy(Axis::Z, 3 / 16)
|
||||
->extendedCopy(Facing::DOWN, 1 / 16) //presumably this is to correct for farmland being 15/16 of a block tall
|
||||
];
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@ final class DoublePitcherCrop extends DoublePlant implements Ageable{
|
||||
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item instanceof Fertilizer && $this->grow($player)){
|
||||
$item->pop();
|
||||
return true;
|
||||
|
@ -45,7 +45,7 @@ class DoublePlant extends Flowable{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$down = $blockReplace->getSide(Facing::DOWN);
|
||||
if($down->hasTypeTag(BlockTypeTags::DIRT) && $blockReplace->getSide(Facing::UP)->canBeReplaced()){
|
||||
$top = clone $this;
|
||||
|
@ -28,6 +28,7 @@ use pocketmine\block\utils\FallableTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\event\block\BlockTeleportEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\GameMode;
|
||||
use pocketmine\player\Player;
|
||||
@ -44,12 +45,12 @@ class DragonEgg extends Transparent implements Fallable{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
$this->teleport();
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onAttack(Item $item, int $face, ?Player $player = null) : bool{
|
||||
public function onAttack(Item $item, Facing $face, ?Player $player = null) : bool{
|
||||
if($player !== null && $player->getGamemode() !== GameMode::CREATIVE){
|
||||
$this->teleport();
|
||||
return true;
|
||||
@ -81,7 +82,7 @@ class DragonEgg extends Transparent implements Fallable{
|
||||
}
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
}
|
||||
|
@ -23,31 +23,27 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\inventory\EnchantInventory;
|
||||
use pocketmine\block\inventory\window\EnchantingTableInventoryWindow;
|
||||
use pocketmine\block\utils\MenuAccessor;
|
||||
use pocketmine\block\utils\MenuAccessorTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
class EnchantingTable extends Transparent{
|
||||
class EnchantingTable extends Transparent implements MenuAccessor{
|
||||
use MenuAccessorTrait;
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->trim(Facing::UP, 0.25)];
|
||||
return [AxisAlignedBB::one()->trimmedCopy(Facing::UP, 0.25)];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($player instanceof Player){
|
||||
//TODO lock
|
||||
|
||||
$player->setCurrentWindow(new EnchantInventory($this->position));
|
||||
}
|
||||
|
||||
return true;
|
||||
protected function newMenu(Player $player, Position $position) : EnchantingTableInventoryWindow{
|
||||
return new EnchantingTableInventoryWindow($player, $position);
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ class EndPortalFrame extends Opaque implements HorizontalFacing{
|
||||
protected bool $eye = false;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->horizontalFacing($this->facing);
|
||||
$w->enum($this->facing);
|
||||
$w->bool($this->eye);
|
||||
}
|
||||
|
||||
@ -52,6 +52,6 @@ class EndPortalFrame extends Opaque implements HorizontalFacing{
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->trim(Facing::UP, 3 / 16)];
|
||||
return [AxisAlignedBB::one()->trimmedCopy(Facing::UP, 3 / 16)];
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ use pocketmine\world\BlockTransaction;
|
||||
class EndRod extends Flowable implements AnyFacing{
|
||||
use AnyFacingTrait;
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$this->facing = $face;
|
||||
if($blockClicked instanceof EndRod && $blockClicked->facing === $this->facing){
|
||||
$this->facing = Facing::opposite($face);
|
||||
@ -61,7 +61,7 @@ class EndRod extends Flowable implements AnyFacing{
|
||||
if($axis === $myAxis){
|
||||
continue;
|
||||
}
|
||||
$bb->squash($axis, 6 / 16);
|
||||
$bb->squashedCopy($axis, 6 / 16);
|
||||
}
|
||||
return [$bb];
|
||||
}
|
||||
|
@ -23,18 +23,31 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\inventory\EnderChestInventory;
|
||||
use pocketmine\block\inventory\window\BlockInventoryWindow;
|
||||
use pocketmine\block\tile\EnderChest as TileEnderChest;
|
||||
use pocketmine\block\utils\AnimatedContainerLike;
|
||||
use pocketmine\block\utils\AnimatedContainerLikeTrait;
|
||||
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
|
||||
use pocketmine\block\utils\HorizontalFacing;
|
||||
use pocketmine\block\utils\MenuAccessorTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\protocol\BlockEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\BlockPosition;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\Position;
|
||||
use pocketmine\world\sound\EnderChestCloseSound;
|
||||
use pocketmine\world\sound\EnderChestOpenSound;
|
||||
use pocketmine\world\sound\Sound;
|
||||
|
||||
class EnderChest extends Transparent implements HorizontalFacing{
|
||||
class EnderChest extends Transparent implements AnimatedContainerLike, HorizontalFacing{
|
||||
use AnimatedContainerLikeTrait {
|
||||
onViewerAdded as private traitOnViewerAdded;
|
||||
onViewerRemoved as private traitOnViewerRemoved;
|
||||
}
|
||||
use MenuAccessorTrait;
|
||||
use FacesOppositePlacingPlayerTrait;
|
||||
|
||||
public function getLightLevel() : int{
|
||||
@ -43,23 +56,19 @@ class EnderChest extends Transparent implements HorizontalFacing{
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
//these are slightly bigger than in PC
|
||||
return [AxisAlignedBB::one()->contract(0.025, 0, 0.025)->trim(Facing::UP, 0.05)];
|
||||
return [AxisAlignedBB::one()->contractedCopy(0.025, 0, 0.025)->trimmedCopy(Facing::UP, 0.05)];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($player instanceof Player){
|
||||
$enderChest = $this->position->getWorld()->getTile($this->position);
|
||||
if($enderChest instanceof TileEnderChest && $this->getSide(Facing::UP)->isTransparent()){
|
||||
$enderChest->setViewerCount($enderChest->getViewerCount() + 1);
|
||||
$player->setCurrentWindow(new EnderChestInventory($this->position, $player->getEnderInventory()));
|
||||
}
|
||||
}
|
||||
public function isOpeningObstructed() : bool{
|
||||
return !$this->getSide(Facing::UP)->isTransparent();
|
||||
}
|
||||
|
||||
return true;
|
||||
protected function newMenu(Player $player, Position $position) : BlockInventoryWindow{
|
||||
return new BlockInventoryWindow($player, $player->getEnderInventory(), $position);
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
@ -71,4 +80,43 @@ class EnderChest extends Transparent implements HorizontalFacing{
|
||||
public function isAffectedBySilkTouch() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getViewerCount() : int{
|
||||
$enderChest = $this->position->getWorld()->getTile($this->position);
|
||||
if(!$enderChest instanceof TileEnderChest){
|
||||
return 0;
|
||||
}
|
||||
return $enderChest->getViewerCount();
|
||||
}
|
||||
|
||||
private function updateViewerCount(int $amount) : void{
|
||||
$enderChest = $this->position->getWorld()->getTile($this->position);
|
||||
if($enderChest instanceof TileEnderChest){
|
||||
$enderChest->setViewerCount($enderChest->getViewerCount() + $amount);
|
||||
}
|
||||
}
|
||||
|
||||
protected function getOpenSound() : Sound{
|
||||
return new EnderChestOpenSound();
|
||||
}
|
||||
|
||||
protected function getCloseSound() : Sound{
|
||||
return new EnderChestCloseSound();
|
||||
}
|
||||
|
||||
protected function playAnimationVisual(Position $position, bool $isOpen) : void{
|
||||
//event ID is always 1 for a chest
|
||||
//TODO: we probably shouldn't be sending a packet directly here, but it doesn't fit anywhere into existing systems
|
||||
$position->getWorld()->broadcastPacketToViewers($position, BlockEventPacket::create(BlockPosition::fromVector3($position), 1, $isOpen ? 1 : 0));
|
||||
}
|
||||
|
||||
public function onViewerAdded() : void{
|
||||
$this->updateViewerCount(1);
|
||||
$this->traitOnViewerAdded();
|
||||
}
|
||||
|
||||
public function onViewerRemoved() : void{
|
||||
$this->traitOnViewerRemoved();
|
||||
$this->updateViewerCount(-1);
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ class Farmland extends Transparent{
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->trim(Facing::UP, 1 / 16)];
|
||||
return [AxisAlignedBB::one()->trimmedCopy(Facing::UP, 1 / 16)];
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
|
@ -45,9 +45,9 @@ class Fence extends Transparent{
|
||||
foreach(Facing::HORIZONTAL as $facing){
|
||||
$block = $this->getSide($facing);
|
||||
if($block instanceof static || $block instanceof FenceGate || $block->getSupportType(Facing::opposite($facing)) === SupportType::FULL){
|
||||
$this->connections[$facing] = true;
|
||||
$this->connections[$facing->value] = true;
|
||||
}else{
|
||||
unset($this->connections[$facing]);
|
||||
unset($this->connections[$facing->value]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,43 +59,43 @@ class Fence extends Transparent{
|
||||
|
||||
$bbs = [];
|
||||
|
||||
$connectWest = isset($this->connections[Facing::WEST]);
|
||||
$connectEast = isset($this->connections[Facing::EAST]);
|
||||
$connectWest = isset($this->connections[Facing::WEST->value]);
|
||||
$connectEast = isset($this->connections[Facing::EAST->value]);
|
||||
|
||||
if($connectWest || $connectEast){
|
||||
//X axis (west/east)
|
||||
$bbs[] = AxisAlignedBB::one()
|
||||
->squash(Axis::Z, $inset)
|
||||
->extend(Facing::UP, 0.5)
|
||||
->trim(Facing::WEST, $connectWest ? 0 : $inset)
|
||||
->trim(Facing::EAST, $connectEast ? 0 : $inset);
|
||||
->squashedCopy(Axis::Z, $inset)
|
||||
->extendedCopy(Facing::UP, 0.5)
|
||||
->trimmedCopy(Facing::WEST, $connectWest ? 0 : $inset)
|
||||
->trimmedCopy(Facing::EAST, $connectEast ? 0 : $inset);
|
||||
}
|
||||
|
||||
$connectNorth = isset($this->connections[Facing::NORTH]);
|
||||
$connectSouth = isset($this->connections[Facing::SOUTH]);
|
||||
$connectNorth = isset($this->connections[Facing::NORTH->value]);
|
||||
$connectSouth = isset($this->connections[Facing::SOUTH->value]);
|
||||
|
||||
if($connectNorth || $connectSouth){
|
||||
//Z axis (north/south)
|
||||
$bbs[] = AxisAlignedBB::one()
|
||||
->squash(Axis::X, $inset)
|
||||
->extend(Facing::UP, 0.5)
|
||||
->trim(Facing::NORTH, $connectNorth ? 0 : $inset)
|
||||
->trim(Facing::SOUTH, $connectSouth ? 0 : $inset);
|
||||
->squashedCopy(Axis::X, $inset)
|
||||
->extendedCopy(Facing::UP, 0.5)
|
||||
->trimmedCopy(Facing::NORTH, $connectNorth ? 0 : $inset)
|
||||
->trimmedCopy(Facing::SOUTH, $connectSouth ? 0 : $inset);
|
||||
}
|
||||
|
||||
if(count($bbs) === 0){
|
||||
//centre post AABB (only needed if not connected on any axis - other BBs overlapping will do this if any connections are made)
|
||||
return [
|
||||
AxisAlignedBB::one()
|
||||
->extend(Facing::UP, 0.5)
|
||||
->contract($inset, 0, $inset)
|
||||
->extendedCopy(Facing::UP, 0.5)
|
||||
->contractedCopy($inset, 0, $inset)
|
||||
];
|
||||
}
|
||||
|
||||
return $bbs;
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return Facing::axis($facing) === Axis::Y ? SupportType::CENTER : SupportType::NONE;
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\HorizontalFacing;
|
||||
use pocketmine\block\utils\HorizontalFacingOption;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\block\utils\WoodMaterial;
|
||||
@ -45,7 +46,7 @@ class FenceGate extends Transparent implements HorizontalFacing, WoodMaterial{
|
||||
protected bool $inWall = false;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->horizontalFacing($this->facing);
|
||||
$w->enum($this->facing);
|
||||
$w->bool($this->open);
|
||||
$w->bool($this->inWall);
|
||||
}
|
||||
@ -67,23 +68,24 @@ class FenceGate extends Transparent implements HorizontalFacing, WoodMaterial{
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return $this->open ? [] : [AxisAlignedBB::one()->extend(Facing::UP, 0.5)->squash(Facing::axis($this->facing), 6 / 16)];
|
||||
return $this->open ? [] : [AxisAlignedBB::one()->extendedCopy(Facing::UP, 0.5)->squashedCopy(Facing::axis($this->facing->toFacing()), 6 / 16)];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
private function checkInWall() : bool{
|
||||
$realFacing = $this->facing->toFacing();
|
||||
return (
|
||||
$this->getSide(Facing::rotateY($this->facing, false)) instanceof Wall ||
|
||||
$this->getSide(Facing::rotateY($this->facing, true)) instanceof Wall
|
||||
$this->getSide(Facing::rotateY($realFacing, false)) instanceof Wall ||
|
||||
$this->getSide(Facing::rotateY($realFacing, true)) instanceof Wall
|
||||
);
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($player !== null){
|
||||
$this->facing = $player->getHorizontalFacing();
|
||||
$this->facing = HorizontalFacingOption::fromFacing($player->getHorizontalFacing());
|
||||
}
|
||||
|
||||
$this->inWall = $this->checkInWall();
|
||||
@ -99,12 +101,12 @@ class FenceGate extends Transparent implements HorizontalFacing, WoodMaterial{
|
||||
}
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
$this->open = !$this->open;
|
||||
if($this->open && $player !== null){
|
||||
$playerFacing = $player->getHorizontalFacing();
|
||||
if($playerFacing === Facing::opposite($this->facing)){
|
||||
$this->facing = $playerFacing;
|
||||
if($playerFacing === Facing::opposite($this->facing->toFacing())){
|
||||
$this->facing = HorizontalFacingOption::fromFacing($playerFacing);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,16 +54,16 @@ abstract class FillableCauldron extends Transparent{
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
$result = [
|
||||
AxisAlignedBB::one()->trim(Facing::UP, 11 / 16) //bottom of the cauldron
|
||||
AxisAlignedBB::one()->trimmedCopy(Facing::UP, 11 / 16) //bottom of the cauldron
|
||||
];
|
||||
|
||||
foreach(Facing::HORIZONTAL as $f){ //add the frame parts around the bowl
|
||||
$result[] = AxisAlignedBB::one()->trim($f, 14 / 16);
|
||||
$result[] = AxisAlignedBB::one()->trimmedCopy($f, 14 / 16);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return $facing === Facing::UP ? SupportType::EDGE : SupportType::NONE;
|
||||
}
|
||||
|
||||
|
@ -38,11 +38,11 @@ final class FloorBanner extends BaseBanner implements SignLikeRotation{
|
||||
return VanillaBlocks::OMINOUS_BANNER()->setRotation($this->rotation);
|
||||
}
|
||||
|
||||
protected function getSupportingFace() : int{
|
||||
protected function getSupportingFace() : Facing{
|
||||
return Facing::DOWN;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($face !== Facing::UP){
|
||||
return false;
|
||||
}
|
||||
|
@ -38,16 +38,16 @@ use function rad2deg;
|
||||
final class FloorCoralFan extends BaseCoral{
|
||||
use StaticSupportTrait;
|
||||
|
||||
private int $axis = Axis::X;
|
||||
private Axis $axis = Axis::X;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->horizontalAxis($this->axis);
|
||||
}
|
||||
|
||||
public function getAxis() : int{ return $this->axis; }
|
||||
public function getAxis() : Axis{ return $this->axis; }
|
||||
|
||||
/** @return $this */
|
||||
public function setAxis(int $axis) : self{
|
||||
public function setAxis(Axis $axis) : self{
|
||||
if($axis !== Axis::X && $axis !== Axis::Z){
|
||||
throw new \InvalidArgumentException("Axis must be X or Z only");
|
||||
}
|
||||
@ -55,7 +55,7 @@ final class FloorCoralFan extends BaseCoral{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($player !== null){
|
||||
$playerBlockPos = $player->getPosition()->floor();
|
||||
$directionVector = $blockReplace->position->subtractVector($playerBlockPos)->normalize();
|
||||
|
@ -34,11 +34,11 @@ use pocketmine\world\BlockTransaction;
|
||||
final class FloorSign extends BaseSign implements SignLikeRotation{
|
||||
use SignLikeRotationTrait;
|
||||
|
||||
protected function getSupportingFace() : int{
|
||||
protected function getSupportingFace() : Facing{
|
||||
return Facing::DOWN;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($face !== Facing::UP){
|
||||
return false;
|
||||
}
|
||||
@ -48,4 +48,8 @@ final class FloorSign extends BaseSign implements SignLikeRotation{
|
||||
}
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
protected function getFacingDegrees() : float{
|
||||
return $this->rotation * 22.5;
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
|
||||
/**
|
||||
@ -40,7 +41,7 @@ abstract class Flowable extends Transparent{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, Facing $face, bool $isClickedBlock) : bool{
|
||||
return (!$this->canBeFlowedInto() || !$blockReplace instanceof Liquid) &&
|
||||
parent::canBePlacedAt($blockReplace, $clickVector, $face, $isClickedBlock);
|
||||
}
|
||||
@ -49,7 +50,7 @@ abstract class Flowable extends Transparent{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
}
|
||||
|
@ -84,14 +84,14 @@ class FlowerPot extends Flowable{
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->contract(3 / 16, 0, 3 / 16)->trim(Facing::UP, 5 / 8)];
|
||||
return [AxisAlignedBB::one()->contractedCopy(3 / 16, 0, 3 / 16)->trimmedCopy(Facing::UP, 5 / 8)];
|
||||
}
|
||||
|
||||
private function canBeSupportedAt(Block $block) : bool{
|
||||
return $block->getAdjacentSupportType(Facing::DOWN)->hasCenterSupport();
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
$world = $this->position->getWorld();
|
||||
$plant = $item->getBlock();
|
||||
if($this->plant !== null){
|
||||
|
@ -23,19 +23,24 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\inventory\window\FurnaceInventoryWindow;
|
||||
use pocketmine\block\tile\Furnace as TileFurnace;
|
||||
use pocketmine\block\utils\Container;
|
||||
use pocketmine\block\utils\ContainerTrait;
|
||||
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
|
||||
use pocketmine\block\utils\HorizontalFacing;
|
||||
use pocketmine\block\utils\Lightable;
|
||||
use pocketmine\block\utils\LightableTrait;
|
||||
use pocketmine\crafting\FurnaceType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\inventory\Inventory;
|
||||
use pocketmine\player\InventoryWindow;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\Position;
|
||||
use function mt_rand;
|
||||
|
||||
class Furnace extends Opaque implements Lightable, HorizontalFacing{
|
||||
class Furnace extends Opaque implements Container, Lightable, HorizontalFacing{
|
||||
use ContainerTrait;
|
||||
use FacesOppositePlacingPlayerTrait;
|
||||
use LightableTrait;
|
||||
|
||||
@ -47,7 +52,7 @@ class Furnace extends Opaque implements Lightable, HorizontalFacing{
|
||||
}
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->horizontalFacing($this->facing);
|
||||
$w->enum($this->facing);
|
||||
$w->bool($this->lit);
|
||||
}
|
||||
|
||||
@ -59,15 +64,8 @@ class Furnace extends Opaque implements Lightable, HorizontalFacing{
|
||||
return $this->lit ? 13 : 0;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($player instanceof Player){
|
||||
$furnace = $this->position->getWorld()->getTile($this->position);
|
||||
if($furnace instanceof TileFurnace && $furnace->canOpenWith($item->getCustomName())){
|
||||
$player->setCurrentWindow($furnace->getInventory());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
protected function newMenu(Player $player, Inventory $inventory, Position $position) : InventoryWindow{
|
||||
return new FurnaceInventoryWindow($player, $inventory, $position, $this->furnaceType);
|
||||
}
|
||||
|
||||
public function onScheduledUpdate() : void{
|
||||
|
@ -51,7 +51,7 @@ class GlowLichen extends Transparent implements MultiAnyFacing{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
@ -60,13 +60,13 @@ class GlowLichen extends Transparent implements MultiAnyFacing{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int[]
|
||||
* @return Facing[]
|
||||
*/
|
||||
protected function getInitialPlaceFaces(Block $blockReplace) : array{
|
||||
return $blockReplace instanceof GlowLichen ? $blockReplace->faces : [];
|
||||
}
|
||||
|
||||
private function getSpreadBlock(Block $replace, int $spreadFace) : ?Block{
|
||||
private function getSpreadBlock(Block $replace, Facing $spreadFace) : ?Block{
|
||||
if($replace instanceof self && $replace->hasSameTypeId($this)){
|
||||
if($replace->hasFace($spreadFace)){
|
||||
return null;
|
||||
@ -81,7 +81,7 @@ class GlowLichen extends Transparent implements MultiAnyFacing{
|
||||
return $result->setFace($spreadFace, true);
|
||||
}
|
||||
|
||||
private function spread(World $world, Vector3 $replacePos, int $spreadFace) : bool{
|
||||
private function spread(World $world, Vector3 $replacePos, Facing $spreadFace) : bool{
|
||||
$supportBlock = $world->getBlock($replacePos->getSide($spreadFace));
|
||||
$supportFace = Facing::opposite($spreadFace);
|
||||
|
||||
@ -99,9 +99,9 @@ class GlowLichen extends Transparent implements MultiAnyFacing{
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-return \Generator<int, int, void, void>
|
||||
* @phpstan-return \Generator<int, Facing, void, void>
|
||||
*/
|
||||
private static function getShuffledSpreadFaces(int $sourceFace) : \Generator{
|
||||
private static function getShuffledSpreadFaces(Facing $sourceFace) : \Generator{
|
||||
$skipAxis = Facing::axis($sourceFace);
|
||||
|
||||
$faces = Facing::ALL;
|
||||
@ -113,7 +113,7 @@ class GlowLichen extends Transparent implements MultiAnyFacing{
|
||||
}
|
||||
}
|
||||
|
||||
private function spreadAroundSupport(int $sourceFace) : bool{
|
||||
private function spreadAroundSupport(Facing $sourceFace) : bool{
|
||||
$world = $this->position->getWorld();
|
||||
|
||||
$supportPos = $this->position->getSide($sourceFace);
|
||||
@ -127,7 +127,7 @@ class GlowLichen extends Transparent implements MultiAnyFacing{
|
||||
return false;
|
||||
}
|
||||
|
||||
private function spreadAdjacentToSupport(int $sourceFace) : bool{
|
||||
private function spreadAdjacentToSupport(Facing $sourceFace) : bool{
|
||||
$world = $this->position->getWorld();
|
||||
|
||||
foreach(self::getShuffledSpreadFaces($sourceFace) as $spreadFace){
|
||||
@ -139,7 +139,7 @@ class GlowLichen extends Transparent implements MultiAnyFacing{
|
||||
return false;
|
||||
}
|
||||
|
||||
private function spreadWithinSelf(int $sourceFace) : bool{
|
||||
private function spreadWithinSelf(Facing $sourceFace) : bool{
|
||||
foreach(self::getShuffledSpreadFaces($sourceFace) as $spreadFace){
|
||||
if(!$this->hasFace($spreadFace) && $this->spread($this->position->getWorld(), $this->position, $spreadFace)){
|
||||
return true;
|
||||
@ -149,7 +149,7 @@ class GlowLichen extends Transparent implements MultiAnyFacing{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item instanceof Fertilizer && count($this->faces) > 0){
|
||||
$shuffledFaces = $this->faces;
|
||||
shuffle($shuffledFaces);
|
||||
|
@ -81,7 +81,7 @@ class Grass extends Opaque{
|
||||
}
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($this->getSide(Facing::UP)->getTypeId() !== BlockTypeIds::AIR){
|
||||
return false;
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ use pocketmine\math\Facing;
|
||||
class GrassPath extends Transparent{
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->trim(Facing::UP, 1 / 16)];
|
||||
return [AxisAlignedBB::one()->trimmedCopy(Facing::UP, 1 / 16)];
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
|
@ -23,32 +23,38 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\tile\Hopper as TileHopper;
|
||||
use pocketmine\block\inventory\window\HopperInventoryWindow;
|
||||
use pocketmine\block\utils\Container;
|
||||
use pocketmine\block\utils\ContainerTrait;
|
||||
use pocketmine\block\utils\PoweredByRedstone;
|
||||
use pocketmine\block\utils\PoweredByRedstoneTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\inventory\Inventory;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\InventoryWindow;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
class Hopper extends Transparent implements PoweredByRedstone{
|
||||
class Hopper extends Transparent implements Container, PoweredByRedstone{
|
||||
use ContainerTrait;
|
||||
use PoweredByRedstoneTrait;
|
||||
|
||||
private int $facing = Facing::DOWN;
|
||||
private Facing $facing = Facing::DOWN;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->facingExcept($this->facing, Facing::UP);
|
||||
$w->bool($this->powered);
|
||||
}
|
||||
|
||||
public function getFacing() : int{ return $this->facing; }
|
||||
public function getFacing() : Facing{ return $this->facing; }
|
||||
|
||||
/** @return $this */
|
||||
public function setFacing(int $facing) : self{
|
||||
public function setFacing(Facing $facing) : self{
|
||||
if($facing === Facing::UP){
|
||||
throw new \InvalidArgumentException("Hopper may not face upward");
|
||||
}
|
||||
@ -58,16 +64,16 @@ class Hopper extends Transparent implements PoweredByRedstone{
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
$result = [
|
||||
AxisAlignedBB::one()->trim(Facing::UP, 6 / 16) //the empty area around the bottom is currently considered solid
|
||||
AxisAlignedBB::one()->trimmedCopy(Facing::UP, 6 / 16) //the empty area around the bottom is currently considered solid
|
||||
];
|
||||
|
||||
foreach(Facing::HORIZONTAL as $f){ //add the frame parts around the bowl
|
||||
$result[] = AxisAlignedBB::one()->trim($f, 14 / 16);
|
||||
$result[] = AxisAlignedBB::one()->trimmedCopy($f, 14 / 16);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return match($facing){
|
||||
Facing::UP => SupportType::FULL,
|
||||
Facing::DOWN => $this->facing === Facing::DOWN ? SupportType::CENTER : SupportType::NONE,
|
||||
@ -75,21 +81,14 @@ class Hopper extends Transparent implements PoweredByRedstone{
|
||||
};
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$this->facing = $face === Facing::DOWN ? Facing::DOWN : Facing::opposite($face);
|
||||
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($player !== null){
|
||||
$tile = $this->position->getWorld()->getTile($this->position);
|
||||
if($tile instanceof TileHopper){ //TODO: find a way to have inventories open on click without this boilerplate in every block
|
||||
$player->setCurrentWindow($tile->getInventory());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
protected function newMenu(Player $player, Inventory $inventory, Position $position) : InventoryWindow{
|
||||
return new HopperInventoryWindow($player, $inventory, $position);
|
||||
}
|
||||
|
||||
public function onScheduledUpdate() : void{
|
||||
|
@ -52,7 +52,7 @@ class ItemFrame extends Flowable implements AnyFacing{
|
||||
protected float $itemDropChance = 1.0;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->facing($this->facing);
|
||||
$w->enum($this->facing);
|
||||
$w->bool($this->hasMap);
|
||||
}
|
||||
|
||||
@ -132,7 +132,7 @@ class ItemFrame extends Flowable implements AnyFacing{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($this->framedItem !== null){
|
||||
$this->itemRotation = ($this->itemRotation + 1) % self::ROTATIONS;
|
||||
|
||||
@ -150,7 +150,7 @@ class ItemFrame extends Flowable implements AnyFacing{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onAttack(Item $item, int $face, ?Player $player = null) : bool{
|
||||
public function onAttack(Item $item, Facing $face, ?Player $player = null) : bool{
|
||||
if($this->framedItem === null){
|
||||
return false;
|
||||
}
|
||||
@ -164,7 +164,7 @@ class ItemFrame extends Flowable implements AnyFacing{
|
||||
return true;
|
||||
}
|
||||
|
||||
private function canBeSupportedAt(Block $block, int $face) : bool{
|
||||
private function canBeSupportedAt(Block $block, Facing $face) : bool{
|
||||
return $block->getAdjacentSupportType($face) !== SupportType::NONE;
|
||||
}
|
||||
|
||||
@ -174,7 +174,7 @@ class ItemFrame extends Flowable implements AnyFacing{
|
||||
}
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$this->canBeSupportedAt($blockReplace, Facing::opposite($face))){
|
||||
return false;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ use pocketmine\block\tile\Jukebox as JukeboxTile;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\Record;
|
||||
use pocketmine\lang\KnownTranslationFactory;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\sound\RecordSound;
|
||||
@ -40,7 +41,7 @@ class Jukebox extends Opaque{
|
||||
return 300;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($player instanceof Player){
|
||||
if($this->record !== null){
|
||||
$this->ejectRecord();
|
||||
|
@ -24,12 +24,12 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\HorizontalFacing;
|
||||
use pocketmine\block\utils\HorizontalFacingOption;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\Living;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
@ -60,16 +60,16 @@ class Ladder extends Transparent implements HorizontalFacing{
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->trim($this->facing, 13 / 16)];
|
||||
return [AxisAlignedBB::one()->trimmedCopy($this->facing->toFacing(), 13 / 16)];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $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)) && Facing::axis($face) !== Axis::Y){
|
||||
$this->facing = $face;
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(($hzFacing = HorizontalFacingOption::tryFromFacing($face)) !== null && $this->canBeSupportedAt($blockReplace, Facing::opposite($face))){
|
||||
$this->facing = $hzFacing;
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
@ -77,12 +77,12 @@ class Ladder extends Transparent implements HorizontalFacing{
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(!$this->canBeSupportedAt($this, Facing::opposite($this->facing))){ //Replace with common break method
|
||||
if(!$this->canBeSupportedAt($this, Facing::opposite($this->facing->toFacing()))){ //Replace with common break method
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
}
|
||||
}
|
||||
|
||||
private function canBeSupportedAt(Block $block, int $face) : bool{
|
||||
private function canBeSupportedAt(Block $block, Facing $face) : bool{
|
||||
return $block->getAdjacentSupportType($face) === SupportType::FULL;
|
||||
}
|
||||
}
|
||||
|
@ -62,18 +62,18 @@ class Lantern extends Transparent{
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [
|
||||
AxisAlignedBB::one()
|
||||
->trim(Facing::UP, $this->hanging ? 6 / 16 : 8 / 16)
|
||||
->trim(Facing::DOWN, $this->hanging ? 2 / 16 : 0)
|
||||
->squash(Axis::X, 5 / 16)
|
||||
->squash(Axis::Z, 5 / 16)
|
||||
->trimmedCopy(Facing::UP, $this->hanging ? 6 / 16 : 8 / 16)
|
||||
->trimmedCopy(Facing::DOWN, $this->hanging ? 2 / 16 : 0)
|
||||
->squashedCopy(Axis::X, 5 / 16)
|
||||
->squashedCopy(Axis::Z, 5 / 16)
|
||||
];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$downSupport = $this->canBeSupportedAt($blockReplace, Facing::DOWN);
|
||||
if(!$downSupport && !$this->canBeSupportedAt($blockReplace, Facing::UP)){
|
||||
return false;
|
||||
@ -90,7 +90,7 @@ class Lantern extends Transparent{
|
||||
}
|
||||
}
|
||||
|
||||
private function canBeSupportedAt(Block $block, int $face) : bool{
|
||||
private function canBeSupportedAt(Block $block, Facing $face) : bool{
|
||||
return $block->getAdjacentSupportType($face)->hasCenterSupport();
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemTypeIds;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\sound\CauldronEmptyLavaSound;
|
||||
@ -61,7 +62,7 @@ final class LavaCauldron extends FillableCauldron{
|
||||
return new CauldronEmptyLavaSound();
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
match($item->getTypeId()){
|
||||
ItemTypeIds::BUCKET => $this->removeFillLevels(self::MAX_FILL_LEVEL, $item, VanillaItems::LAVA_BUCKET(), $returnedItems),
|
||||
ItemTypeIds::POWDER_SNOW_BUCKET, ItemTypeIds::WATER_BUCKET => $this->mix($item, VanillaItems::BUCKET(), $returnedItems),
|
||||
|
@ -134,7 +134,7 @@ class Leaves extends Transparent{
|
||||
}
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$this->noDecay = true; //artificial leaves don't decay
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
@ -188,7 +188,7 @@ class Leaves extends Transparent{
|
||||
return 60;
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ class Lectern extends Transparent implements HorizontalFacing{
|
||||
protected bool $producingSignal = false;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->horizontalFacing($this->facing);
|
||||
$w->enum($this->facing);
|
||||
$w->bool($this->producingSignal);
|
||||
}
|
||||
|
||||
@ -84,10 +84,10 @@ class Lectern extends Transparent implements HorizontalFacing{
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->trim(Facing::UP, 0.1)];
|
||||
return [AxisAlignedBB::one()->trimmedCopy(Facing::UP, 0.1)];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
@ -120,7 +120,7 @@ class Lectern extends Transparent implements HorizontalFacing{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($this->book === null && $item instanceof WritableBookBase){
|
||||
$world = $this->position->getWorld();
|
||||
$world->setBlock($this->position, $this->setBook($item));
|
||||
@ -130,7 +130,7 @@ class Lectern extends Transparent implements HorizontalFacing{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onAttack(Item $item, int $face, ?Player $player = null) : bool{
|
||||
public function onAttack(Item $item, Facing $face, ?Player $player = null) : bool{
|
||||
if($this->book !== null){
|
||||
$world = $this->position->getWorld();
|
||||
$world->dropItem($this->position->up(), $this->book);
|
||||
|
@ -30,7 +30,6 @@ use pocketmine\math\Axis;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\sound\RedstonePowerOffSound;
|
||||
use pocketmine\world\sound\RedstonePowerOnSound;
|
||||
@ -60,7 +59,7 @@ class Lever extends Flowable{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$this->canBeSupportedAt($blockReplace, Facing::opposite($face))){
|
||||
return false;
|
||||
}
|
||||
@ -78,7 +77,6 @@ class Lever extends Flowable{
|
||||
Facing::SOUTH => LeverFacing::SOUTH,
|
||||
Facing::WEST => LeverFacing::WEST,
|
||||
Facing::EAST => LeverFacing::EAST,
|
||||
default => throw new AssumptionFailedError("Bad facing value"),
|
||||
};
|
||||
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
@ -90,7 +88,7 @@ class Lever extends Flowable{
|
||||
}
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
$this->activated = !$this->activated;
|
||||
$world = $this->position->getWorld();
|
||||
$world->setBlock($this->position, $this);
|
||||
@ -101,7 +99,7 @@ class Lever extends Flowable{
|
||||
return true;
|
||||
}
|
||||
|
||||
private function canBeSupportedAt(Block $block, int $face) : bool{
|
||||
private function canBeSupportedAt(Block $block, Facing $face) : bool{
|
||||
return $block->getAdjacentSupportType($face)->hasCenterSupport();
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
@ -51,12 +52,12 @@ final class Light extends Flowable{
|
||||
|
||||
public function canBeReplaced() : bool{ return true; }
|
||||
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, Facing $face, bool $isClickedBlock) : bool{
|
||||
//light blocks behave like solid blocks when placing them on another light block
|
||||
return $blockReplace->canBeReplaced() && $blockReplace->getTypeId() !== $this->getTypeId();
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
$this->level = $this->level === self::MAX_LIGHT_LEVEL ?
|
||||
self::MIN_LIGHT_LEVEL :
|
||||
$this->level + 1;
|
||||
|
@ -42,14 +42,14 @@ final class LightningRod extends Transparent implements AnyFacing{
|
||||
$result = AxisAlignedBB::one();
|
||||
foreach([Axis::X, Axis::Y, Axis::Z] as $axis){
|
||||
if($axis !== $myAxis){
|
||||
$result->squash($axis, 6 / 16);
|
||||
$result = $result->squashedCopy($axis, 6 / 16);
|
||||
}
|
||||
}
|
||||
|
||||
return [$result];
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$this->facing = $face;
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ abstract class Liquid extends Transparent{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
@ -170,7 +170,7 @@ abstract class Liquid extends Transparent{
|
||||
$world = $this->position->getWorld();
|
||||
|
||||
foreach(Facing::HORIZONTAL as $j){
|
||||
[$dx, $dy, $dz] = Facing::OFFSET[$j];
|
||||
[$dx, $dy, $dz] = Facing::OFFSET[$j->value];
|
||||
|
||||
$sideX = $x + $dx;
|
||||
$sideY = $y + $dy;
|
||||
@ -206,7 +206,7 @@ abstract class Liquid extends Transparent{
|
||||
|
||||
if($this->falling){
|
||||
foreach(Facing::HORIZONTAL as $facing){
|
||||
[$dx, $dy, $dz] = Facing::OFFSET[$facing];
|
||||
[$dx, $dy, $dz] = Facing::OFFSET[$facing->value];
|
||||
if(
|
||||
!$this->canFlowInto($world->getBlockAt($x + $dx, $y + $dy, $z + $dz)) ||
|
||||
!$this->canFlowInto($world->getBlockAt($x + $dx, $y + $dy + 1, $z + $dz))
|
||||
|
@ -23,21 +23,19 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\inventory\LoomInventory;
|
||||
use pocketmine\block\inventory\window\LoomInventoryWindow;
|
||||
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
|
||||
use pocketmine\block\utils\HorizontalFacing;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\block\utils\MenuAccessor;
|
||||
use pocketmine\block\utils\MenuAccessorTrait;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
final class Loom extends Opaque implements HorizontalFacing{
|
||||
final class Loom extends Opaque implements HorizontalFacing, MenuAccessor{
|
||||
use FacesOppositePlacingPlayerTrait;
|
||||
use MenuAccessorTrait;
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($player !== null){
|
||||
$player->setCurrentWindow(new LoomInventory($this->position));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
protected function newMenu(Player $player, Position $position) : LoomInventoryWindow{
|
||||
return new LoomInventoryWindow($player, $position);
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ class MobHead extends Flowable{
|
||||
|
||||
protected MobHeadType $mobHeadType = MobHeadType::SKELETON;
|
||||
|
||||
protected int $facing = Facing::NORTH;
|
||||
protected Facing $facing = Facing::NORTH;
|
||||
protected int $rotation = self::MIN_ROTATION; //TODO: split this into floor skull and wall skull handling
|
||||
|
||||
public function describeBlockItemState(RuntimeDataDescriber $w) : void{
|
||||
@ -82,10 +82,10 @@ class MobHead extends Flowable{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFacing() : int{ return $this->facing; }
|
||||
public function getFacing() : Facing{ return $this->facing; }
|
||||
|
||||
/** @return $this */
|
||||
public function setFacing(int $facing) : self{
|
||||
public function setFacing(Facing $facing) : self{
|
||||
if($facing === Facing::DOWN){
|
||||
throw new \InvalidArgumentException("Skull may not face DOWN");
|
||||
}
|
||||
@ -106,17 +106,17 @@ class MobHead extends Flowable{
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
$collisionBox = AxisAlignedBB::one()
|
||||
->contract(0.25, 0, 0.25)
|
||||
->trim(Facing::UP, 0.5);
|
||||
->contractedCopy(0.25, 0, 0.25)
|
||||
->trimmedCopy(Facing::UP, 0.5);
|
||||
if($this->facing !== Facing::UP){
|
||||
$collisionBox = $collisionBox
|
||||
->offsetTowards(Facing::opposite($this->facing), 0.25)
|
||||
->offsetTowards(Facing::UP, 0.25);
|
||||
->offsetTowardsCopy(Facing::opposite($this->facing), 0.25)
|
||||
->offsetTowardsCopy(Facing::UP, 0.25);
|
||||
}
|
||||
return [$collisionBox];
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($face === Facing::DOWN){
|
||||
return false;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use function mt_rand;
|
||||
|
||||
class MonsterSpawner extends Transparent{
|
||||
@ -41,7 +42,7 @@ class MonsterSpawner extends Transparent{
|
||||
//TODO
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
}
|
||||
|
@ -28,16 +28,17 @@ use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\Facing;
|
||||
|
||||
class NetherPortal extends Transparent{
|
||||
|
||||
protected int $axis = Axis::X;
|
||||
protected Axis $axis = Axis::X;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->horizontalAxis($this->axis);
|
||||
}
|
||||
|
||||
public function getAxis() : int{
|
||||
public function getAxis() : Axis{
|
||||
return $this->axis;
|
||||
}
|
||||
|
||||
@ -45,7 +46,7 @@ class NetherPortal extends Transparent{
|
||||
* @throws \InvalidArgumentException
|
||||
* @return $this
|
||||
*/
|
||||
public function setAxis(int $axis) : self{
|
||||
public function setAxis(Axis $axis) : self{
|
||||
if($axis !== Axis::X && $axis !== Axis::Z){
|
||||
throw new \InvalidArgumentException("Invalid axis");
|
||||
}
|
||||
@ -65,7 +66,7 @@ class NetherPortal extends Transparent{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
|
@ -49,9 +49,9 @@ class NetherVines extends Flowable implements Ageable{
|
||||
public const MAX_AGE = 25;
|
||||
|
||||
/** Direction the vine grows towards. */
|
||||
private int $growthFace;
|
||||
private Facing $growthFace;
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo, int $growthFace){
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo, Facing $growthFace){
|
||||
$this->growthFace = $growthFace;
|
||||
parent::__construct($idInfo, $name, $typeInfo);
|
||||
}
|
||||
@ -80,12 +80,12 @@ class NetherVines extends Flowable implements Ageable{
|
||||
return $top;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$this->age = mt_rand(0, self::MAX_AGE - 1);
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item instanceof Fertilizer){
|
||||
if($this->grow($player, mt_rand(1, 5))){
|
||||
$item->pop();
|
||||
@ -159,7 +159,7 @@ class NetherVines extends Flowable implements Ageable{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
}
|
||||
|
@ -36,11 +36,11 @@ final class OminousFloorBanner extends BaseOminousBanner implements SignLikeRota
|
||||
|
||||
//TODO: duplicated code :(
|
||||
|
||||
protected function getSupportingFace() : int{
|
||||
protected function getSupportingFace() : Facing{
|
||||
return Facing::DOWN;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($face !== Facing::UP){
|
||||
return false;
|
||||
}
|
||||
|
@ -24,9 +24,9 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\HorizontalFacing;
|
||||
use pocketmine\block\utils\HorizontalFacingOption;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
@ -35,15 +35,16 @@ use pocketmine\world\BlockTransaction;
|
||||
final class OminousWallBanner extends BaseOminousBanner implements HorizontalFacing{
|
||||
use HorizontalFacingTrait;
|
||||
|
||||
protected function getSupportingFace() : int{
|
||||
return Facing::opposite($this->facing);
|
||||
protected function getSupportingFace() : Facing{
|
||||
return Facing::opposite($this->facing->toFacing());
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(Facing::axis($face) === Axis::Y){
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$hzFacing = HorizontalFacingOption::tryFromFacing($face);
|
||||
if($hzFacing === null){
|
||||
return false;
|
||||
}
|
||||
$this->facing = $face;
|
||||
$this->facing = $hzFacing;
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\HorizontalFacing;
|
||||
use pocketmine\block\utils\HorizontalFacingOption;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\StaticSupportTrait;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
@ -47,7 +48,7 @@ class PinkPetals extends Flowable implements HorizontalFacing{
|
||||
protected int $count = self::MIN_COUNT;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->horizontalFacing($this->facing);
|
||||
$w->enum($this->facing);
|
||||
$w->boundedIntAuto(self::MIN_COUNT, self::MAX_COUNT, $this->count);
|
||||
}
|
||||
|
||||
@ -70,21 +71,21 @@ class PinkPetals extends Flowable implements HorizontalFacing{
|
||||
return $supportBlock->hasTypeTag(BlockTypeTags::DIRT) || $supportBlock->hasTypeTag(BlockTypeTags::MUD);
|
||||
}
|
||||
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, Facing $face, bool $isClickedBlock) : bool{
|
||||
return ($blockReplace instanceof PinkPetals && $blockReplace->count < self::MAX_COUNT) || $this->supportedWhenPlacedAt($blockReplace, $clickVector, $face, $isClickedBlock);
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($blockReplace instanceof PinkPetals && $blockReplace->count < self::MAX_COUNT){
|
||||
$this->count = $blockReplace->count + 1;
|
||||
$this->facing = $blockReplace->facing;
|
||||
}elseif($player !== null){
|
||||
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
||||
$this->facing = HorizontalFacingOption::fromFacing(Facing::opposite($player->getHorizontalFacing()));
|
||||
}
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item instanceof Fertilizer){
|
||||
$grew = false;
|
||||
if($this->count < self::MAX_COUNT){
|
||||
|
@ -54,10 +54,10 @@ final class PitcherCrop extends Flowable implements Ageable{
|
||||
$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
|
||||
->trimmedCopy(Facing::UP, $heightTrim / 16)
|
||||
->squashedCopy(Axis::X, $widthTrim / 16)
|
||||
->squashedCopy(Axis::Z, $widthTrim / 16)
|
||||
->extendedCopy(Facing::DOWN, 1 / 16) //presumably this is to correct for farmland being 15/16 of a block tall
|
||||
];
|
||||
}
|
||||
|
||||
@ -85,7 +85,7 @@ final class PitcherCrop extends Flowable implements Ageable{
|
||||
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{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item instanceof Fertilizer && $this->grow($player)){
|
||||
$item->pop();
|
||||
return true;
|
||||
|
@ -27,6 +27,7 @@ use pocketmine\block\tile\Cauldron as TileCauldron;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemTypeIds;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\sound\CauldronEmptyPotionSound;
|
||||
@ -94,7 +95,7 @@ final class PotionCauldron extends FillableCauldron{
|
||||
}
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
match($item->getTypeId()){
|
||||
ItemTypeIds::LINGERING_POTION, ItemTypeIds::POTION, ItemTypeIds::SPLASH_POTION => $this->addFillLevelsOrMix(self::POTION_FILL_AMOUNT, $item, VanillaItems::GLASS_BOTTLE(), $returnedItems),
|
||||
ItemTypeIds::GLASS_BOTTLE => $this->potionItem === null ? null : $this->removeFillLevels(self::POTION_FILL_AMOUNT, $item, clone $this->potionItem, $returnedItems),
|
||||
|
@ -57,7 +57,7 @@ abstract class PressurePlate extends Transparent{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
public function getSupportType(Facing $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
@ -83,10 +83,10 @@ abstract class PressurePlate extends Transparent{
|
||||
*/
|
||||
protected function getActivationBox() : AxisAlignedBB{
|
||||
return AxisAlignedBB::one()
|
||||
->squash(Axis::X, 1 / 8)
|
||||
->squash(Axis::Z, 1 / 8)
|
||||
->trim(Facing::UP, 3 / 4)
|
||||
->offset($this->position->x, $this->position->y, $this->position->z);
|
||||
->squashedCopy(Axis::X, 1 / 8)
|
||||
->squashedCopy(Axis::Z, 1 / 8)
|
||||
->trimmedCopy(Facing::UP, 3 / 4)
|
||||
->offsetCopy($this->position->x, $this->position->y, $this->position->z);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,21 +23,21 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\HorizontalFacingOption;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\Shears;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use function in_array;
|
||||
|
||||
class Pumpkin extends Opaque{
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item instanceof Shears && in_array($face, Facing::HORIZONTAL, true)){
|
||||
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item instanceof Shears && ($hzFacing = HorizontalFacingOption::tryFromFacing($face)) !== null){
|
||||
$item->applyDamage(1);
|
||||
$world = $this->position->getWorld();
|
||||
$world->setBlock($this->position, VanillaBlocks::CARVED_PUMPKIN()->setFacing($face));
|
||||
$world->setBlock($this->position, VanillaBlocks::CARVED_PUMPKIN()->setFacing($hzFacing));
|
||||
$world->dropItem($this->position->add(0.5, 0.5, 0.5), VanillaItems::PUMPKIN_SEEDS()->setCount(1));
|
||||
return true;
|
||||
}
|
||||
|
@ -24,18 +24,16 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\RailConnectionInfo;
|
||||
use pocketmine\data\bedrock\block\BlockLegacyMetadata;
|
||||
use pocketmine\block\utils\RailShape;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\math\Facing;
|
||||
use function array_keys;
|
||||
use function implode;
|
||||
|
||||
class Rail extends BaseRail{
|
||||
|
||||
private int $railShape = BlockLegacyMetadata::RAIL_STRAIGHT_NORTH_SOUTH;
|
||||
private RailShape $railShape = RailShape::FLAT_AXIS_Z;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->railShape($this->railShape);
|
||||
$w->enum($this->railShape);
|
||||
}
|
||||
|
||||
protected function setShapeFromConnections(array $connections) : void{
|
||||
@ -43,11 +41,11 @@ class Rail extends BaseRail{
|
||||
if($railShape === null){
|
||||
throw new \InvalidArgumentException("No rail shape matches these connections");
|
||||
}
|
||||
$this->railShape = $railShape;
|
||||
$this->railShape = RailShape::from($railShape);
|
||||
}
|
||||
|
||||
protected function getCurrentShapeConnections() : array{
|
||||
return RailConnectionInfo::CURVE_CONNECTIONS[$this->railShape] ?? RailConnectionInfo::CONNECTIONS[$this->railShape];
|
||||
return RailConnectionInfo::CURVE_CONNECTIONS[$this->railShape->value] ?? RailConnectionInfo::CONNECTIONS[$this->railShape->value];
|
||||
}
|
||||
|
||||
protected function getPossibleConnectionDirectionsOneConstraint(int $constraint) : array{
|
||||
@ -60,8 +58,8 @@ class Rail extends BaseRail{
|
||||
Facing::WEST,
|
||||
Facing::EAST
|
||||
] as $d){
|
||||
if($constraint !== $d){
|
||||
$possible[$d] = true;
|
||||
if($constraint !== $d->value){
|
||||
$possible[$d->value] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -69,13 +67,10 @@ class Rail extends BaseRail{
|
||||
return $possible;
|
||||
}
|
||||
|
||||
public function getShape() : int{ return $this->railShape; }
|
||||
public function getShape() : RailShape{ return $this->railShape; }
|
||||
|
||||
/** @return $this */
|
||||
public function setShape(int $shape) : self{
|
||||
if(!isset(RailConnectionInfo::CONNECTIONS[$shape]) && !isset(RailConnectionInfo::CURVE_CONNECTIONS[$shape])){
|
||||
throw new \InvalidArgumentException("Invalid shape, must be one of " . implode(", ", [...array_keys(RailConnectionInfo::CONNECTIONS), ...array_keys(RailConnectionInfo::CURVE_CONNECTIONS)]));
|
||||
}
|
||||
public function setShape(RailShape $shape) : self{
|
||||
$this->railShape = $shape;
|
||||
return $this;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user