Merge branch 'minor-next' into major-next

This commit is contained in:
Dylan K. Taylor
2023-07-24 12:07:55 +01:00
55 changed files with 247 additions and 224 deletions

View File

@ -13,7 +13,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup PHP and tools - name: Setup PHP and tools
uses: shivammathur/setup-php@2.25.2 uses: shivammathur/setup-php@2.25.4
with: with:
php-version: 8.1 php-version: 8.1

View File

@ -18,7 +18,7 @@ jobs:
submodules: true submodules: true
- name: Setup PHP - name: Setup PHP
uses: shivammathur/setup-php@2.25.2 uses: shivammathur/setup-php@2.25.4
with: with:
php-version: 8.1 php-version: 8.1

View File

@ -173,7 +173,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup PHP and tools - name: Setup PHP and tools
uses: shivammathur/setup-php@2.25.2 uses: shivammathur/setup-php@2.25.4
with: with:
php-version: 8.1 php-version: 8.1
tools: php-cs-fixer:3.17 tools: php-cs-fixer:3.17

View File

@ -50,7 +50,7 @@
"pocketmine/raklib-ipc": "^0.2.0", "pocketmine/raklib-ipc": "^0.2.0",
"pocketmine/snooze": "^0.5.0", "pocketmine/snooze": "^0.5.0",
"ramsey/uuid": "~4.7.0", "ramsey/uuid": "~4.7.0",
"symfony/filesystem": "~6.2.0" "symfony/filesystem": "~6.3.0"
}, },
"require-dev": { "require-dev": {
"phpstan/phpstan": "1.10.16", "phpstan/phpstan": "1.10.16",

27
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "ee46ec27f8dfc8c767527b7776fe9992", "content-hash": "74166e6c2f09b356c83a951efef349f2",
"packages": [ "packages": [
{ {
"name": "adhocore/json-comment", "name": "adhocore/json-comment",
@ -998,16 +998,16 @@
}, },
{ {
"name": "symfony/filesystem", "name": "symfony/filesystem",
"version": "v6.2.12", "version": "v6.3.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/filesystem.git", "url": "https://github.com/symfony/filesystem.git",
"reference": "b0818e7203e53540f2a5c9a5017d97897df1e9bb" "reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/b0818e7203e53540f2a5c9a5017d97897df1e9bb", "url": "https://api.github.com/repos/symfony/filesystem/zipball/edd36776956f2a6fcf577edb5b05eb0e3bdc52ae",
"reference": "b0818e7203e53540f2a5c9a5017d97897df1e9bb", "reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1041,7 +1041,7 @@
"description": "Provides basic utilities for the filesystem", "description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/filesystem/tree/v6.2.12" "source": "https://github.com/symfony/filesystem/tree/v6.3.1"
}, },
"funding": [ "funding": [
{ {
@ -1057,7 +1057,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-06-01T08:29:37+00:00" "time": "2023-06-01T08:30:39+00:00"
}, },
{ {
"name": "symfony/polyfill-ctype", "name": "symfony/polyfill-ctype",
@ -2546,16 +2546,16 @@
}, },
{ {
"name": "sebastian/global-state", "name": "sebastian/global-state",
"version": "6.0.0", "version": "6.0.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git", "url": "https://github.com/sebastianbergmann/global-state.git",
"reference": "aab257c712de87b90194febd52e4d184551c2d44" "reference": "7ea9ead78f6d380d2a667864c132c2f7b83055e4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/aab257c712de87b90194febd52e4d184551c2d44", "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/7ea9ead78f6d380d2a667864c132c2f7b83055e4",
"reference": "aab257c712de87b90194febd52e4d184551c2d44", "reference": "7ea9ead78f6d380d2a667864c132c2f7b83055e4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2595,7 +2595,8 @@
], ],
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues", "issues": "https://github.com/sebastianbergmann/global-state/issues",
"source": "https://github.com/sebastianbergmann/global-state/tree/6.0.0" "security": "https://github.com/sebastianbergmann/global-state/security/policy",
"source": "https://github.com/sebastianbergmann/global-state/tree/6.0.1"
}, },
"funding": [ "funding": [
{ {
@ -2603,7 +2604,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-02-03T07:07:38+00:00" "time": "2023-07-19T07:19:23+00:00"
}, },
{ {
"name": "sebastian/lines-of-code", "name": "sebastian/lines-of-code",

View File

@ -341,7 +341,7 @@ JIT_WARNING
if(ThreadManager::getInstance()->stopAll() > 0){ if(ThreadManager::getInstance()->stopAll() > 0){
$logger->debug("Some threads could not be stopped, performing a force-kill"); $logger->debug("Some threads could not be stopped, performing a force-kill");
Process::kill(Process::pid(), true); Process::kill(Process::pid());
} }
}while(false); }while(false);

View File

@ -1011,7 +1011,7 @@ class Server{
$this->playerDataProvider = new DatFilePlayerDataProvider(Path::join($this->dataPath, "players")); $this->playerDataProvider = new DatFilePlayerDataProvider(Path::join($this->dataPath, "players"));
register_shutdown_function([$this, "crashDump"]); register_shutdown_function($this->crashDump(...));
$loadErrorCount = 0; $loadErrorCount = 0;
$this->pluginManager->loadPlugins($this->pluginPath, $loadErrorCount); $this->pluginManager->loadPlugins($this->pluginPath, $loadErrorCount);
@ -1429,7 +1429,7 @@ class Server{
private function forceShutdownExit() : void{ private function forceShutdownExit() : void{
$this->forceShutdown(); $this->forceShutdown();
Process::kill(Process::pid(), true); Process::kill(Process::pid());
} }
public function forceShutdown() : void{ public function forceShutdown() : void{
@ -1497,7 +1497,7 @@ class Server{
}catch(\Throwable $e){ }catch(\Throwable $e){
$this->logger->logException($e); $this->logger->logException($e);
$this->logger->emergency("Crashed while crashing, killing process"); $this->logger->emergency("Crashed while crashing, killing process");
@Process::kill(Process::pid(), true); @Process::kill(Process::pid());
} }
} }
@ -1651,7 +1651,7 @@ class Server{
echo "--- Waiting $spacing seconds to throttle automatic restart (you can kill the process safely now) ---" . PHP_EOL; echo "--- Waiting $spacing seconds to throttle automatic restart (you can kill the process safely now) ---" . PHP_EOL;
sleep($spacing); sleep($spacing);
} }
@Process::kill(Process::pid(), true); @Process::kill(Process::pid());
exit(1); exit(1);
} }

View File

@ -38,7 +38,7 @@ use function in_array;
abstract class BaseRail extends Flowable{ 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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($blockReplace->getSide(Facing::DOWN)->getSupportType(Facing::UP)->hasEdgeSupport()){ if($blockReplace->getAdjacentSupportType(Facing::DOWN)->hasEdgeSupport()){
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
} }
@ -222,7 +222,7 @@ abstract class BaseRail extends Flowable{
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
$world = $this->position->getWorld(); $world = $this->position->getWorld();
if(!$this->getSide(Facing::DOWN)->getSupportType(Facing::UP)->hasEdgeSupport()){ if(!$this->getAdjacentSupportType(Facing::DOWN)->hasEdgeSupport()){
$world->useBreakOn($this->position); $world->useBreakOn($this->position);
}else{ }else{
foreach($this->getCurrentShapeConnections() as $connection){ foreach($this->getCurrentShapeConnections() as $connection){

View File

@ -177,11 +177,11 @@ class Bed 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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->canBeSupportedBy($this->getSide(Facing::DOWN))){ if($this->canBeSupportedAt($blockReplace)){
$this->facing = $player !== null ? $player->getHorizontalFacing() : Facing::NORTH; $this->facing = $player !== null ? $player->getHorizontalFacing() : Facing::NORTH;
$next = $this->getSide($this->getOtherHalfSide()); $next = $this->getSide($this->getOtherHalfSide());
if($next->canBeReplaced() && $this->canBeSupportedBy($next->getSide(Facing::DOWN))){ if($next->canBeReplaced() && $this->canBeSupportedAt($next)){
$nextState = clone $this; $nextState = clone $this;
$nextState->head = true; $nextState->head = true;
$tx->addBlock($blockReplace->position, $this)->addBlock($next->position, $nextState); $tx->addBlock($blockReplace->position, $this)->addBlock($next->position, $nextState);
@ -208,8 +208,8 @@ class Bed extends Transparent{
return parent::getAffectedBlocks(); return parent::getAffectedBlocks();
} }
private function canBeSupportedBy(Block $block) : bool{ private function canBeSupportedAt(Block $block) : bool{
return !$block->getSupportType(Facing::UP)->equals(SupportType::NONE()); return !$block->getAdjacentSupportType(Facing::DOWN)->equals(SupportType::NONE());
} }
public function getMaxStackSize() : int{ return 1; } public function getMaxStackSize() : int{ return 1; }

View File

@ -35,6 +35,7 @@ use pocketmine\math\Facing;
use pocketmine\math\RayTraceResult; use pocketmine\math\RayTraceResult;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\player\Player; use pocketmine\player\Player;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\world\BlockTransaction; use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\BellRingSound; use pocketmine\world\sound\BellRingSound;
@ -87,46 +88,44 @@ final class Bell extends Transparent{
return $this; return $this;
} }
private function canBeSupportedBy(Block $block, int $face) : bool{ private function canBeSupportedAt(Block $block, int $face) : bool{
return !$block->getSupportType($face)->equals(SupportType::NONE()); return !$block->getAdjacentSupportType($face)->equals(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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedAt($blockReplace, Facing::opposite($face))){
return false;
}
if($face === Facing::UP){ if($face === Facing::UP){
if(!$this->canBeSupportedBy($tx->fetchBlock($this->position->down()), Facing::UP)){
return false;
}
if($player !== null){ if($player !== null){
$this->setFacing(Facing::opposite($player->getHorizontalFacing())); $this->setFacing(Facing::opposite($player->getHorizontalFacing()));
} }
$this->setAttachmentType(BellAttachmentType::FLOOR()); $this->setAttachmentType(BellAttachmentType::FLOOR());
}elseif($face === Facing::DOWN){ }elseif($face === Facing::DOWN){
if(!$this->canBeSupportedBy($tx->fetchBlock($this->position->up()), Facing::DOWN)){
return false;
}
$this->setAttachmentType(BellAttachmentType::CEILING()); $this->setAttachmentType(BellAttachmentType::CEILING());
}else{ }else{
$this->setFacing($face); $this->setFacing($face);
if($this->canBeSupportedBy($tx->fetchBlock($this->position->getSide(Facing::opposite($face))), $face)){ $this->setAttachmentType(
$this->setAttachmentType(BellAttachmentType::ONE_WALL()); $this->canBeSupportedAt($blockReplace, $face) ?
}else{ BellAttachmentType::TWO_WALLS() :
return false; BellAttachmentType::ONE_WALL()
} );
if($this->canBeSupportedBy($tx->fetchBlock($this->position->getSide($face)), Facing::opposite($face))){
$this->setAttachmentType(BellAttachmentType::TWO_WALLS());
}
} }
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
if( foreach(match($this->attachmentType){
($this->attachmentType->equals(BellAttachmentType::CEILING()) && !$this->canBeSupportedBy($this->getSide(Facing::UP), Facing::DOWN)) || BellAttachmentType::CEILING() => [Facing::UP],
($this->attachmentType->equals(BellAttachmentType::FLOOR()) && !$this->canBeSupportedBy($this->getSide(Facing::DOWN), Facing::UP)) || BellAttachmentType::FLOOR() => [Facing::DOWN],
($this->attachmentType->equals(BellAttachmentType::ONE_WALL()) && !$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)), $this->facing)) || BellAttachmentType::ONE_WALL() => [Facing::opposite($this->facing)],
($this->attachmentType->equals(BellAttachmentType::TWO_WALLS()) && (!$this->canBeSupportedBy($this->getSide($this->facing), Facing::opposite($this->facing)) || !$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)), $this->facing))) BellAttachmentType::TWO_WALLS() => [$this->facing, Facing::opposite($this->facing)],
){ default => throw new AssumptionFailedError("All cases of BellAttachmentType must be handled")
$this->position->getWorld()->useBreakOn($this->position); } as $supportBlockDirection){
if(!$this->canBeSupportedAt($this, $supportBlockDirection)){
$this->position->getWorld()->useBreakOn($this->position);
break;
}
} }
} }
@ -159,13 +158,11 @@ final class Bell extends Transparent{
} }
private function isValidFaceToRing(int $faceHit) : bool{ private function isValidFaceToRing(int $faceHit) : bool{
return ( return match($this->attachmentType){
$this->attachmentType->equals(BellAttachmentType::CEILING()) || BellAttachmentType::CEILING() => true,
($this->attachmentType->equals(BellAttachmentType::FLOOR()) && Facing::axis($faceHit) === Facing::axis($this->facing)) || 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),
($this->attachmentType->equals(BellAttachmentType::ONE_WALL()) || $this->attachmentType->equals(BellAttachmentType::TWO_WALLS())) && default => throw new AssumptionFailedError("All cases of BellAttachmentType must be handled")
($faceHit === Facing::rotateY($this->facing, false) || $faceHit === Facing::rotateY($this->facing, true)) };
)
);
} }
} }

View File

@ -41,6 +41,7 @@ use pocketmine\item\Item;
use pocketmine\item\ItemBlock; use pocketmine\item\ItemBlock;
use pocketmine\math\Axis; use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\RayTraceResult; use pocketmine\math\RayTraceResult;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
@ -863,6 +864,10 @@ class Block{
return SupportType::FULL(); return SupportType::FULL();
} }
protected function getAdjacentSupportType(int $facing) : SupportType{
return $this->getSide($facing)->getSupportType(Facing::opposite($facing));
}
public function isFullCube() : bool{ public function isFullCube() : bool{
$bb = $this->getCollisionBoxes(); $bb = $this->getCollisionBoxes();

View File

@ -52,7 +52,7 @@ abstract class Button 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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->canBeSupportedBy($blockReplace->getSide(Facing::opposite($face)), $face)){ if($this->canBeSupportedAt($blockReplace, $face)){
$this->facing = $face; $this->facing = $face;
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
} }
@ -83,12 +83,12 @@ abstract class Button extends Flowable{
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)), $this->facing)){ if(!$this->canBeSupportedAt($this, $this->facing)){
$this->position->getWorld()->useBreakOn($this->position); $this->position->getWorld()->useBreakOn($this->position);
} }
} }
private function canBeSupportedBy(Block $support, int $face) : bool{ private function canBeSupportedAt(Block $block, int $face) : bool{
return $support->getSupportType($face)->hasCenterSupport(); return $block->getAdjacentSupportType(Facing::opposite($face))->hasCenterSupport();
} }
} }

View File

@ -104,8 +104,7 @@ class Candle 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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$down = $blockReplace->getSide(Facing::DOWN); if(!$blockReplace->getAdjacentSupportType(Facing::DOWN)->hasCenterSupport()){
if(!$down->getSupportType(Facing::UP)->hasCenterSupport()){
return false; return false;
} }
$existing = $this->getCandleIfCompatibleType($blockReplace); $existing = $this->getCandleIfCompatibleType($blockReplace);

View File

@ -87,18 +87,18 @@ class CaveVines extends Flowable{
return $this->berries ? 14 : 0; return $this->berries ? 14 : 0;
} }
private function canBeSupportedBy(Block $block) : bool{ private function canBeSupportedAt(Block $block) : bool{
return $block->getSupportType(Facing::DOWN)->equals(SupportType::FULL()) || $block->hasSameTypeId($this); return $block->getAdjacentSupportType(Facing::UP)->equals(SupportType::FULL()) || $block->hasSameTypeId($this);
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedBy($this->getSide(Facing::UP))){ if(!$this->canBeSupportedAt($this)){
$this->position->getWorld()->useBreakOn($this->position); $this->position->getWorld()->useBreakOn($this->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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedBy($blockReplace->getSide(Facing::UP))){ if(!$this->canBeSupportedAt($blockReplace)){
return false; return false;
} }
$this->age = mt_rand(0, self::MAX_AGE); $this->age = mt_rand(0, self::MAX_AGE);

View File

@ -32,7 +32,7 @@ use pocketmine\world\BlockTransaction;
final class Coral extends BaseCoral{ final class Coral extends BaseCoral{
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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedBy($tx->fetchBlock($blockReplace->getPosition()->down()))){ if(!$this->canBeSupportedAt($blockReplace)){
return false; return false;
} }
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
@ -40,14 +40,14 @@ final class Coral extends BaseCoral{
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
$world = $this->position->getWorld(); $world = $this->position->getWorld();
if(!$this->canBeSupportedBy($world->getBlock($this->position->down()))){ if(!$this->canBeSupportedAt($this)){
$world->useBreakOn($this->position); $world->useBreakOn($this->position);
}else{ }else{
parent::onNearbyBlockChange(); parent::onNearbyBlockChange();
} }
} }
private function canBeSupportedBy(Block $block) : bool{ private function canBeSupportedAt(Block $block) : bool{
return $block->getSupportType(Facing::UP)->hasCenterSupport(); return $block->getAdjacentSupportType(Facing::DOWN)->hasCenterSupport();
} }
} }

View File

@ -106,7 +106,7 @@ class Door extends Transparent{
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedBy($this->getSide(Facing::DOWN)) && !$this->getSide(Facing::DOWN) instanceof Door){ //Replace with common break method if(!$this->canBeSupportedAt($this) && !$this->getSide(Facing::DOWN) instanceof Door){ //Replace with common break method
$this->position->getWorld()->useBreakOn($this->position); //this will delete both halves if they exist $this->position->getWorld()->useBreakOn($this->position); //this will delete both halves if they exist
} }
} }
@ -114,8 +114,7 @@ class Door 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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($face === Facing::UP){ if($face === Facing::UP){
$blockUp = $this->getSide(Facing::UP); $blockUp = $this->getSide(Facing::UP);
$blockDown = $this->getSide(Facing::DOWN); if(!$blockUp->canBeReplaced() || !$this->canBeSupportedAt($blockReplace)){
if(!$blockUp->canBeReplaced() || !$this->canBeSupportedBy($blockDown)){
return false; return false;
} }
@ -172,7 +171,7 @@ class Door extends Transparent{
return parent::getAffectedBlocks(); return parent::getAffectedBlocks();
} }
private function canBeSupportedBy(Block $block) : bool{ private function canBeSupportedAt(Block $block) : bool{
return $block->getSupportType(Facing::UP)->hasEdgeSupport(); return $block->getAdjacentSupportType(Facing::DOWN)->hasEdgeSupport();
} }
} }

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber; use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\event\block\BlockBurnEvent; use pocketmine\event\block\BlockBurnEvent;
use pocketmine\event\block\BlockSpreadEvent; use pocketmine\event\block\BlockSpreadEvent;
@ -58,12 +59,16 @@ class Fire extends BaseFire{
return 1; return 1;
} }
private function canBeSupportedBy(Block $block) : bool{
return $block->getSupportType(Facing::UP)->equals(SupportType::FULL());
}
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
$world = $this->position->getWorld(); $world = $this->position->getWorld();
$down = $this->getSide(Facing::DOWN); $down = $this->getSide(Facing::DOWN);
if(SoulFire::canBeSupportedBy($down)){ if(SoulFire::canBeSupportedBy($down)){
$world->setBlock($this->position, VanillaBlocks::SOUL_FIRE()); $world->setBlock($this->position, VanillaBlocks::SOUL_FIRE());
}elseif($down->isTransparent() && !$this->hasAdjacentFlammableBlocks()){ }elseif(!$this->canBeSupportedBy($this->getSide(Facing::DOWN)) && !$this->hasAdjacentFlammableBlocks()){
$world->setBlock($this->position, VanillaBlocks::AIR()); $world->setBlock($this->position, VanillaBlocks::AIR());
}else{ }else{
$world->scheduleDelayedBlockUpdate($this->position, mt_rand(30, 40)); $world->scheduleDelayedBlockUpdate($this->position, mt_rand(30, 40));

View File

@ -53,7 +53,7 @@ final class FloorCoralFan extends BaseCoral{
} }
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedBy($tx->fetchBlock($blockReplace->getPosition()->down()))){ if(!$this->canBeSupportedAt($blockReplace)){
return false; return false;
} }
if($player !== null){ if($player !== null){
@ -75,15 +75,15 @@ final class FloorCoralFan extends BaseCoral{
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
$world = $this->position->getWorld(); $world = $this->position->getWorld();
if(!$this->canBeSupportedBy($world->getBlock($this->position->down()))){ if(!$this->canBeSupportedAt($this)){
$world->useBreakOn($this->position); $world->useBreakOn($this->position);
}else{ }else{
parent::onNearbyBlockChange(); parent::onNearbyBlockChange();
} }
} }
private function canBeSupportedBy(Block $block) : bool{ private function canBeSupportedAt(Block $block) : bool{
return $block->getSupportType(Facing::UP)->hasCenterSupport(); return $block->getAdjacentSupportType(Facing::DOWN)->hasCenterSupport();
} }
public function asItem() : Item{ public function asItem() : Item{

View File

@ -90,7 +90,7 @@ class FlowerPot 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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedBy($this->getSide(Facing::DOWN))){ if(!$this->canBeSupportedAt($blockReplace)){
return false; return false;
} }
@ -98,13 +98,13 @@ class FlowerPot extends Flowable{
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedBy($this->getSide(Facing::DOWN))){ if(!$this->canBeSupportedAt($this)){
$this->position->getWorld()->useBreakOn($this->position); $this->position->getWorld()->useBreakOn($this->position);
} }
} }
private function canBeSupportedBy(Block $block) : bool{ private function canBeSupportedAt(Block $block) : bool{
return $block->getSupportType(Facing::UP)->hasCenterSupport(); 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, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{

View File

@ -48,12 +48,7 @@ class FrostedIce extends Ice{
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
$world = $this->position->getWorld(); $this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, mt_rand(20, 40));
if(!$this->checkAdjacentBlocks(2)){
$world->useBreakOn($this->position);
}else{
$world->scheduleDelayedBlockUpdate($this->position, mt_rand(20, 40));
}
} }
public function onRandomTick() : void{ public function onRandomTick() : void{

View File

@ -121,7 +121,7 @@ class GlowLichen extends Transparent{
$changed = false; $changed = false;
foreach($this->faces as $face){ foreach($this->faces as $face){
if(!$this->getSide($face)->getSupportType(Facing::opposite($face))->equals(SupportType::FULL())){ if(!$this->getAdjacentSupportType($face)->equals(SupportType::FULL())){
unset($this->faces[$face]); unset($this->faces[$face]);
$changed = true; $changed = true;
} }
@ -275,7 +275,7 @@ class GlowLichen extends Transparent{
private function getAvailableFaces() : array{ private function getAvailableFaces() : array{
$faces = []; $faces = [];
foreach(Facing::ALL as $face){ foreach(Facing::ALL as $face){
if(!$this->hasFace($face) && $this->getSide($face)->getSupportType(Facing::opposite($face))->equals(SupportType::FULL())){ if(!$this->hasFace($face) && $this->getAdjacentSupportType($face)->equals(SupportType::FULL())){
$faces[$face] = $face; $faces[$face] = $face;
} }
} }

View File

@ -163,18 +163,18 @@ class ItemFrame extends Flowable{
return true; return true;
} }
private function canBeSupportedBy(Block $block, int $face) : bool{ private function canBeSupportedAt(Block $block, int $face) : bool{
return !$block->getSupportType($face)->equals(SupportType::NONE()); return !$block->getAdjacentSupportType($face)->equals(SupportType::NONE());
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)), $this->facing)){ if(!$this->canBeSupportedAt($this, Facing::opposite($this->facing))){
$this->position->getWorld()->useBreakOn($this->position); $this->position->getWorld()->useBreakOn($this->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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedBy($blockReplace->getSide(Facing::opposite($face)), $face)){ if(!$this->canBeSupportedAt($blockReplace, Facing::opposite($face))){
return false; return false;
} }

View File

@ -70,7 +70,7 @@ class Ladder 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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->canBeSupportedBy($blockReplace->getSide(Facing::opposite($face)), $face) && Facing::axis($face) !== Axis::Y){ if($this->canBeSupportedAt($blockReplace, Facing::opposite($face)) && Facing::axis($face) !== Axis::Y){
$this->facing = $face; $this->facing = $face;
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
} }
@ -79,12 +79,12 @@ class Ladder extends Transparent{
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)), $this->facing)){ //Replace with common break method if(!$this->canBeSupportedAt($this, Facing::opposite($this->facing))){ //Replace with common break method
$this->position->getWorld()->useBreakOn($this->position); $this->position->getWorld()->useBreakOn($this->position);
} }
} }
private function canBeSupportedBy(Block $block, int $face) : bool{ private function canBeSupportedAt(Block $block, int $face) : bool{
return $block->getSupportType($face)->equals(SupportType::FULL()); return $block->getAdjacentSupportType($face)->equals(SupportType::FULL());
} }
} }

View File

@ -77,22 +77,23 @@ class Lantern 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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedBy($blockReplace->getSide(Facing::UP), Facing::DOWN) && !$this->canBeSupportedBy($blockReplace->getSide(Facing::DOWN), Facing::UP)){ $downSupport = $this->canBeSupportedAt($blockReplace, Facing::DOWN);
if(!$downSupport && !$this->canBeSupportedAt($blockReplace, Facing::UP)){
return false; return false;
} }
$this->hanging = ($face === Facing::DOWN || !$this->canBeSupportedBy($this->position->getWorld()->getBlock($blockReplace->getPosition()->down()), Facing::UP)); $this->hanging = $face === Facing::DOWN || !$downSupport;
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
$face = $this->hanging ? Facing::UP : Facing::DOWN; $face = $this->hanging ? Facing::UP : Facing::DOWN;
if(!$this->canBeSupportedBy($this->getSide($face), Facing::opposite($face))){ if(!$this->canBeSupportedAt($this, $face)){
$this->position->getWorld()->useBreakOn($this->position); $this->position->getWorld()->useBreakOn($this->position);
} }
} }
private function canBeSupportedBy(Block $block, int $face) : bool{ private function canBeSupportedAt(Block $block, int $face) : bool{
return $block->getSupportType($face)->hasCenterSupport(); return $block->getAdjacentSupportType($face)->hasCenterSupport();
} }
} }

View File

@ -66,7 +66,7 @@ class Lever 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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedBy($blockReplace->getSide(Facing::opposite($face)), $face)){ if(!$this->canBeSupportedAt($blockReplace, Facing::opposite($face))){
return false; return false;
} }
@ -90,8 +90,7 @@ class Lever extends Flowable{
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
$facing = $this->facing->getFacing(); if(!$this->canBeSupportedAt($this, Facing::opposite($this->facing->getFacing()))){
if(!$this->canBeSupportedBy($this->getSide(Facing::opposite($facing)), $facing)){
$this->position->getWorld()->useBreakOn($this->position); $this->position->getWorld()->useBreakOn($this->position);
} }
} }
@ -107,8 +106,8 @@ class Lever extends Flowable{
return true; return true;
} }
private function canBeSupportedBy(Block $block, int $face) : bool{ private function canBeSupportedAt(Block $block, int $face) : bool{
return $block->getSupportType($face)->hasCenterSupport(); return $block->getAdjacentSupportType($face)->hasCenterSupport();
} }
//TODO //TODO

View File

@ -312,7 +312,7 @@ abstract class Liquid extends Transparent{
} }
if($adjacentDecay <= self::MAX_DECAY){ if($adjacentDecay <= self::MAX_DECAY){
$calculator = new MinimumCostFlowCalculator($world, $this->getFlowDecayPerBlock(), \Closure::fromCallable([$this, 'canFlowInto'])); $calculator = new MinimumCostFlowCalculator($world, $this->getFlowDecayPerBlock(), $this->canFlowInto(...));
foreach($calculator->getOptimalFlowDirections($this->position->getFloorX(), $this->position->getFloorY(), $this->position->getFloorZ()) as $facing){ foreach($calculator->getOptimalFlowDirections($this->position->getFloorX(), $this->position->getFloorY(), $this->position->getFloorZ()) as $facing){
$this->flowIntoBlock($world->getBlock($this->position->getSide($facing)), $adjacentDecay, false); $this->flowIntoBlock($world->getBlock($this->position->getSide($facing)), $adjacentDecay, false);
} }

View File

@ -83,16 +83,13 @@ class NetherVines extends Flowable{
return true; return true;
} }
private function getSupportFace() : int{ private function canBeSupportedAt(Block $block) : bool{
return Facing::opposite($this->growthFace); $supportBlock = $block->getSide(Facing::opposite($this->growthFace));
} return $supportBlock->getSupportType($this->growthFace)->hasCenterSupport() || $supportBlock->hasSameTypeId($this);
private function canBeSupportedBy(Block $block) : bool{
return $block->getSupportType($this->getSupportFace())->hasCenterSupport() || $block->hasSameTypeId($this);
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedBy($this->getSide($this->getSupportFace()))){ if(!$this->canBeSupportedAt($this)){
$this->position->getWorld()->useBreakOn($this->position); $this->position->getWorld()->useBreakOn($this->position);
} }
} }
@ -109,7 +106,7 @@ class NetherVines 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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedBy($blockReplace->getSide($this->getSupportFace()))){ if(!$this->canBeSupportedAt($blockReplace)){
return false; return false;
} }
$this->age = mt_rand(0, self::MAX_AGE - 1); $this->age = mt_rand(0, self::MAX_AGE - 1);

View File

@ -45,18 +45,18 @@ abstract class PressurePlate 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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->canBeSupportedBy($blockReplace->getSide(Facing::DOWN))){ if($this->canBeSupportedAt($blockReplace)){
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
} }
return false; return false;
} }
private function canBeSupportedBy(Block $block) : bool{ private function canBeSupportedAt(Block $block) : bool{
return !$block->getSupportType(Facing::UP)->equals(SupportType::NONE()); return !$block->getAdjacentSupportType(Facing::DOWN)->equals(SupportType::NONE());
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedBy($this->getSide(Facing::DOWN))){ if(!$this->canBeSupportedAt($this)){
$this->position->getWorld()->useBreakOn($this->position); $this->position->getWorld()->useBreakOn($this->position);
} }
} }

View File

@ -85,7 +85,7 @@ class RedstoneComparator 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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->canBeSupportedBy($blockReplace->getSide(Facing::DOWN))){ if($this->canBeSupportedAt($blockReplace)){
if($player !== null){ if($player !== null){
$this->facing = Facing::opposite($player->getHorizontalFacing()); $this->facing = Facing::opposite($player->getHorizontalFacing());
} }
@ -102,13 +102,13 @@ class RedstoneComparator extends Flowable{
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedBy($this->getSide(Facing::DOWN))){ if(!$this->canBeSupportedAt($this)){
$this->position->getWorld()->useBreakOn($this->position); $this->position->getWorld()->useBreakOn($this->position);
} }
} }
private function canBeSupportedBy(Block $block) : bool{ private function canBeSupportedAt(Block $block) : bool{
return !$block->getSupportType(Facing::UP)->equals(SupportType::NONE()); return !$block->getAdjacentSupportType(Facing::DOWN)->equals(SupportType::NONE());
} }
//TODO: redstone functionality //TODO: redstone functionality

View File

@ -68,7 +68,7 @@ class RedstoneRepeater 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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->canBeSupportedBy($blockReplace->getSide(Facing::DOWN))){ if($this->canBeSupportedAt($blockReplace)){
if($player !== null){ if($player !== null){
$this->facing = Facing::opposite($player->getHorizontalFacing()); $this->facing = Facing::opposite($player->getHorizontalFacing());
} }
@ -88,13 +88,13 @@ class RedstoneRepeater extends Flowable{
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedBy($this->getSide(Facing::DOWN))){ if(!$this->canBeSupportedAt($this)){
$this->position->getWorld()->useBreakOn($this->position); $this->position->getWorld()->useBreakOn($this->position);
} }
} }
private function canBeSupportedBy(Block $block) : bool{ private function canBeSupportedAt(Block $block) : bool{
return !$block->getSupportType(Facing::UP)->equals(SupportType::NONE()); return !$block->getAdjacentSupportType(Facing::DOWN)->equals(SupportType::NONE());
} }
//TODO: redstone functionality //TODO: redstone functionality

View File

@ -35,7 +35,7 @@ class RedstoneWire extends Flowable{
use AnalogRedstoneSignalEmitterTrait; use AnalogRedstoneSignalEmitterTrait;
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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->canBeSupportedBy($this->getSide(Facing::DOWN))){ if($this->canBeSupportedAt($blockReplace)){
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
} }
return false; return false;
@ -49,13 +49,13 @@ class RedstoneWire extends Flowable{
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedBy($this->getSide(Facing::DOWN))){ if(!$this->canBeSupportedAt($this)){
$this->position->getWorld()->useBreakOn($this->position); $this->position->getWorld()->useBreakOn($this->position);
} }
} }
private function canBeSupportedBy(Block $block) : bool{ private function canBeSupportedAt(Block $block) : bool{
return $block->getSupportType(Facing::UP)->hasCenterSupport(); return $block->getAdjacentSupportType(Facing::DOWN)->hasCenterSupport();
} }
public function asItem() : Item{ public function asItem() : Item{

View File

@ -25,6 +25,7 @@ namespace pocketmine\block;
use pocketmine\block\tile\ShulkerBox as TileShulkerBox; use pocketmine\block\tile\ShulkerBox as TileShulkerBox;
use pocketmine\block\utils\AnyFacingTrait; use pocketmine\block\utils\AnyFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber; use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
@ -110,4 +111,8 @@ class ShulkerBox extends Opaque{
return true; return true;
} }
public function getSupportType(int $facing) : SupportType{
return SupportType::NONE();
}
} }

View File

@ -80,8 +80,8 @@ class SnowLayer extends Flowable implements Fallable{
return SupportType::NONE(); return SupportType::NONE();
} }
private function canBeSupportedBy(Block $b) : bool{ private function canBeSupportedAt(Block $block) : bool{
return $b->getSupportType(Facing::UP)->equals(SupportType::FULL()); return $block->getAdjacentSupportType(Facing::DOWN)->equals(SupportType::FULL());
} }
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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
@ -91,7 +91,7 @@ class SnowLayer extends Flowable implements Fallable{
} }
$this->layers = $blockReplace->layers + 1; $this->layers = $blockReplace->layers + 1;
} }
if($this->canBeSupportedBy($blockReplace->getSide(Facing::DOWN))){ if($this->canBeSupportedAt($blockReplace)){
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
} }

View File

@ -32,12 +32,12 @@ use pocketmine\world\BlockTransaction;
final class SporeBlossom extends Flowable{ final class SporeBlossom extends Flowable{
private function canBeSupportedBy(Block $block) : bool{ private function canBeSupportedAt(Block $block) : bool{
return $block->getSupportType(Facing::DOWN)->equals(SupportType::FULL()); return $block->getAdjacentSupportType(Facing::UP)->equals(SupportType::FULL());
} }
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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedBy($blockReplace->getSide(Facing::UP))){ if(!$this->canBeSupportedAt($blockReplace)){
return false; return false;
} }
@ -45,7 +45,7 @@ final class SporeBlossom extends Flowable{
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedBy($this->getSide(Facing::UP))){ if(!$this->canBeSupportedAt($this)){
$this->position->getWorld()->useBreakOn($this->position); $this->position->getWorld()->useBreakOn($this->position);
} }
} }

View File

@ -26,7 +26,6 @@ namespace pocketmine\block;
use pocketmine\block\utils\SupportType; use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber; use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\math\Axis;
use pocketmine\math\Facing; use pocketmine\math\Facing;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\player\Player; use pocketmine\player\Player;
@ -56,15 +55,13 @@ class Torch extends Flowable{
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
$face = Facing::opposite($this->facing); if(!$this->canBeSupportedAt($this, Facing::opposite($this->facing))){
if(!$this->canBeSupportedBy($this->getSide($face), $this->facing)){
$this->position->getWorld()->useBreakOn($this->position); $this->position->getWorld()->useBreakOn($this->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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($face !== Facing::DOWN && $this->canBeSupportedBy($blockReplace->getSide(Facing::opposite($face)), $face)){ if($face !== Facing::DOWN && $this->canBeSupportedAt($blockReplace, Facing::opposite($face))){
$this->facing = $face; $this->facing = $face;
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}else{ }else{
@ -75,8 +72,7 @@ class Torch extends Flowable{
Facing::EAST, Facing::EAST,
Facing::DOWN Facing::DOWN
] as $side){ ] as $side){
$block = $this->getSide($side); if($this->canBeSupportedAt($blockReplace, $side)){
if($this->canBeSupportedBy($block, Facing::opposite($side))){
$this->facing = Facing::opposite($side); $this->facing = Facing::opposite($side);
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
} }
@ -85,8 +81,9 @@ class Torch extends Flowable{
return false; return false;
} }
private function canBeSupportedBy(Block $support, int $face) : bool{ private function canBeSupportedAt(Block $block, int $face) : bool{
return ($face === Facing::UP && $support->getSupportType($face)->hasCenterSupport()) || return $face === Facing::DOWN ?
(Facing::axis($face) !== Axis::Y && $support->getSupportType($face)->equals(SupportType::FULL())); $block->getAdjacentSupportType($face)->hasCenterSupport() :
$block->getAdjacentSupportType($face)->equals(SupportType::FULL());
} }
} }

View File

@ -42,7 +42,7 @@ final class WallCoralFan extends BaseCoral{
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, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$axis = Facing::axis($face); $axis = Facing::axis($face);
if(($axis !== Axis::X && $axis !== Axis::Z) || !$this->canBeSupportedBy($blockReplace->getSide(Facing::opposite($face)), $face)){ if(($axis !== Axis::X && $axis !== Axis::Z) || !$this->canBeSupportedAt($blockReplace, Facing::opposite($face))){
return false; return false;
} }
$this->facing = $face; $this->facing = $face;
@ -54,15 +54,15 @@ final class WallCoralFan extends BaseCoral{
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
$world = $this->position->getWorld(); $world = $this->position->getWorld();
if(!$this->canBeSupportedBy($world->getBlock($this->position->getSide(Facing::opposite($this->facing))), $this->facing)){ if(!$this->canBeSupportedAt($this, Facing::opposite($this->facing))){
$world->useBreakOn($this->position); $world->useBreakOn($this->position);
}else{ }else{
parent::onNearbyBlockChange(); parent::onNearbyBlockChange();
} }
} }
private function canBeSupportedBy(Block $block, int $face) : bool{ private function canBeSupportedAt(Block $block, int $face) : bool{
return $block->getSupportType($face)->hasCenterSupport(); return $block->getAdjacentSupportType($face)->hasCenterSupport();
} }
public function asItem() : Item{ public function asItem() : Item{

View File

@ -53,7 +53,7 @@ class KillCommand extends VanillaCommand{
return true; return true;
} }
$player->attack(new EntityDamageEvent($player, EntityDamageEvent::CAUSE_SUICIDE, 1000)); $player->attack(new EntityDamageEvent($player, EntityDamageEvent::CAUSE_SUICIDE, $player->getHealth()));
if($player === $sender){ if($player === $sender){
$sender->sendMessage(KnownTranslationFactory::commands_kill_successful($sender->getName())); $sender->sendMessage(KnownTranslationFactory::commands_kill_successful($sender->getName()));
}else{ }else{

View File

@ -94,4 +94,4 @@ while(!feof($socket)){
//For simplicity's sake, we don't bother with a graceful shutdown here. //For simplicity's sake, we don't bother with a graceful shutdown here.
//The parent process would normally forcibly terminate the child process anyway, so we only reach this point if the //The parent process would normally forcibly terminate the child process anyway, so we only reach this point if the
//parent process was terminated forcibly and didn't clean up after itself. //parent process was terminated forcibly and didn't clean up after itself.
Process::kill(Process::pid(), false); Process::kill(Process::pid());

View File

@ -209,9 +209,6 @@ final class CraftingManagerFromDataHelper{
public static function make(string $directoryPath) : CraftingManager{ public static function make(string $directoryPath) : CraftingManager{
$result = new CraftingManager(); $result = new CraftingManager();
$ingredientDeserializerFunc = \Closure::fromCallable([self::class, "deserializeIngredient"]);
$itemDeserializerFunc = \Closure::fromCallable([self::class, 'deserializeItemStack']);
foreach(self::loadJsonArrayOfObjectsFile(Path::join($directoryPath, 'shapeless_crafting.json'), ShapelessRecipeData::class) as $recipe){ foreach(self::loadJsonArrayOfObjectsFile(Path::join($directoryPath, 'shapeless_crafting.json'), ShapelessRecipeData::class) as $recipe){
$recipeType = match($recipe->block){ $recipeType = match($recipe->block){
"crafting_table" => ShapelessRecipeType::CRAFTING(), "crafting_table" => ShapelessRecipeType::CRAFTING(),
@ -225,7 +222,7 @@ final class CraftingManagerFromDataHelper{
} }
$inputs = []; $inputs = [];
foreach($recipe->input as $inputData){ foreach($recipe->input as $inputData){
$input = $ingredientDeserializerFunc($inputData); $input = self::deserializeIngredient($inputData);
if($input === null){ //unknown input item if($input === null){ //unknown input item
continue 2; continue 2;
} }
@ -233,7 +230,7 @@ final class CraftingManagerFromDataHelper{
} }
$outputs = []; $outputs = [];
foreach($recipe->output as $outputData){ foreach($recipe->output as $outputData){
$output = $itemDeserializerFunc($outputData); $output = self::deserializeItemStack($outputData);
if($output === null){ //unknown output item if($output === null){ //unknown output item
continue 2; continue 2;
} }
@ -251,7 +248,7 @@ final class CraftingManagerFromDataHelper{
} }
$inputs = []; $inputs = [];
foreach(Utils::stringifyKeys($recipe->input) as $symbol => $inputData){ foreach(Utils::stringifyKeys($recipe->input) as $symbol => $inputData){
$input = $ingredientDeserializerFunc($inputData); $input = self::deserializeIngredient($inputData);
if($input === null){ //unknown input item if($input === null){ //unknown input item
continue 2; continue 2;
} }
@ -259,7 +256,7 @@ final class CraftingManagerFromDataHelper{
} }
$outputs = []; $outputs = [];
foreach($recipe->output as $outputData){ foreach($recipe->output as $outputData){
$output = $itemDeserializerFunc($outputData); $output = self::deserializeItemStack($outputData);
if($output === null){ //unknown output item if($output === null){ //unknown output item
continue 2; continue 2;
} }

View File

@ -519,7 +519,12 @@ abstract class Entity{
} }
public function attack(EntityDamageEvent $source) : void{ public function attack(EntityDamageEvent $source) : void{
if($this->isFireProof() && ($source->getCause() === EntityDamageEvent::CAUSE_FIRE || $source->getCause() === EntityDamageEvent::CAUSE_FIRE_TICK)){ if($this->isFireProof() && (
$source->getCause() === EntityDamageEvent::CAUSE_FIRE ||
$source->getCause() === EntityDamageEvent::CAUSE_FIRE_TICK ||
$source->getCause() === EntityDamageEvent::CAUSE_LAVA
)
){
$source->cancel(); $source->cancel();
} }
$source->call(); $source->call();
@ -686,8 +691,10 @@ abstract class Entity{
if($fireTicks < 0 || $fireTicks > 0x7fff){ if($fireTicks < 0 || $fireTicks > 0x7fff){
throw new \InvalidArgumentException("Fire ticks must be in range 0 ... " . 0x7fff . ", got $fireTicks"); throw new \InvalidArgumentException("Fire ticks must be in range 0 ... " . 0x7fff . ", got $fireTicks");
} }
$this->fireTicks = $fireTicks; if(!$this->isFireProof()){
$this->networkPropertiesDirty = true; $this->fireTicks = $fireTicks;
$this->networkPropertiesDirty = true;
}
} }
public function extinguish() : void{ public function extinguish() : void{
@ -700,12 +707,13 @@ abstract class Entity{
} }
protected function doOnFireTick(int $tickDiff = 1) : bool{ protected function doOnFireTick(int $tickDiff = 1) : bool{
if($this->isFireProof() && $this->fireTicks > 1){ if($this->isFireProof() && $this->isOnFire()){
$this->fireTicks = 1; $this->extinguish();
}else{ return false;
$this->fireTicks -= $tickDiff;
} }
$this->fireTicks -= $tickDiff;
if(($this->fireTicks % 20 === 0) || $tickDiff > 20){ if(($this->fireTicks % 20 === 0) || $tickDiff > 20){
$this->dealFireDamage(); $this->dealFireDamage();
} }

View File

@ -507,7 +507,7 @@ abstract class Living extends Entity{
} }
public function attack(EntityDamageEvent $source) : void{ public function attack(EntityDamageEvent $source) : void{
if($this->noDamageTicks > 0){ if($this->noDamageTicks > 0 && $source->getCause() !== EntityDamageEvent::CAUSE_SUICIDE){
$source->cancel(); $source->cancel();
} }
@ -520,7 +520,9 @@ abstract class Living extends Entity{
$source->cancel(); $source->cancel();
} }
$this->applyDamageModifiers($source); if($source->getCause() !== EntityDamageEvent::CAUSE_SUICIDE){
$this->applyDamageModifiers($source);
}
if($source instanceof EntityDamageByEntityEvent && ( if($source instanceof EntityDamageByEntityEvent && (
$source->getCause() === EntityDamageEvent::CAUSE_BLOCK_EXPLOSION || $source->getCause() === EntityDamageEvent::CAUSE_BLOCK_EXPLOSION ||

View File

@ -108,7 +108,7 @@ class InventoryManager{
private NetworkSession $session private NetworkSession $session
){ ){
$this->containerOpenCallbacks = new ObjectSet(); $this->containerOpenCallbacks = new ObjectSet();
$this->containerOpenCallbacks->add(\Closure::fromCallable([self::class, 'createContainerOpen'])); $this->containerOpenCallbacks->add(self::createContainerOpen(...));
$this->add(ContainerIds::INVENTORY, $this->player->getInventory()); $this->add(ContainerIds::INVENTORY, $this->player->getInventory());
$this->add(ContainerIds::OFFHAND, $this->player->getOffHandInventory()); $this->add(ContainerIds::OFFHAND, $this->player->getOffHandInventory());
@ -116,9 +116,7 @@ class InventoryManager{
$this->addComplex(UIInventorySlotOffset::CURSOR, $this->player->getCursorInventory()); $this->addComplex(UIInventorySlotOffset::CURSOR, $this->player->getCursorInventory());
$this->addComplex(UIInventorySlotOffset::CRAFTING2X2_INPUT, $this->player->getCraftingGrid()); $this->addComplex(UIInventorySlotOffset::CRAFTING2X2_INPUT, $this->player->getCraftingGrid());
$this->player->getInventory()->getHeldItemIndexChangeListeners()->add(function() : void{ $this->player->getInventory()->getHeldItemIndexChangeListeners()->add($this->syncSelectedHotbarSlot(...));
$this->syncSelectedHotbarSlot();
});
} }
private function associateIdWithInventory(int $id, Inventory $inventory) : void{ private function associateIdWithInventory(int $id, Inventory $inventory) : void{

View File

@ -197,7 +197,7 @@ class NetworkSession{
$this->setHandler(new SessionStartPacketHandler( $this->setHandler(new SessionStartPacketHandler(
$this, $this,
fn() => $this->onSessionStartSuccess() $this->onSessionStartSuccess(...)
)); ));
$this->manager->add($this); $this->manager->add($this);
@ -225,13 +225,13 @@ class NetworkSession{
$this->logger->setPrefix($this->getLogPrefix()); $this->logger->setPrefix($this->getLogPrefix());
$this->manager->markLoginReceived($this); $this->manager->markLoginReceived($this);
}, },
\Closure::fromCallable([$this, "setAuthenticationStatus"]) $this->setAuthenticationStatus(...)
)); ));
} }
protected function createPlayer() : void{ protected function createPlayer() : void{
$this->server->createPlayer($this, $this->info, $this->authenticated, $this->cachedOfflinePlayerData)->onCompletion( $this->server->createPlayer($this, $this->info, $this->authenticated, $this->cachedOfflinePlayerData)->onCompletion(
\Closure::fromCallable([$this, 'onPlayerCreated']), $this->onPlayerCreated(...),
function() : void{ function() : void{
//TODO: this should never actually occur... right? //TODO: this should never actually occur... right?
$this->logger->error("Failed to create player"); $this->logger->error("Failed to create player");
@ -787,9 +787,7 @@ class NetworkSession{
$this->cipher = EncryptionContext::fakeGCM($encryptionKey); $this->cipher = EncryptionContext::fakeGCM($encryptionKey);
$this->setHandler(new HandshakePacketHandler(function() : void{ $this->setHandler(new HandshakePacketHandler($this->onServerLoginSuccess(...)));
$this->onServerLoginSuccess();
}));
$this->logger->debug("Enabled encryption"); $this->logger->debug("Enabled encryption");
})); }));
}else{ }else{
@ -818,9 +816,7 @@ class NetworkSession{
public function notifyTerrainReady() : void{ public function notifyTerrainReady() : void{
$this->logger->debug("Sending spawn notification, waiting for spawn response"); $this->logger->debug("Sending spawn notification, waiting for spawn response");
$this->sendDataPacket(PlayStatusPacket::create(PlayStatusPacket::PLAYER_SPAWN)); $this->sendDataPacket(PlayStatusPacket::create(PlayStatusPacket::PLAYER_SPAWN));
$this->setHandler(new SpawnResponsePacketHandler(function() : void{ $this->setHandler(new SpawnResponsePacketHandler($this->onClientSpawnResponse(...)));
$this->onClientSpawnResponse();
}));
} }
private function onClientSpawnResponse() : void{ private function onClientSpawnResponse() : void{

View File

@ -139,6 +139,6 @@ final class StandardEntityEventBroadcaster implements EntityEventBroadcaster{
} }
public function onEmote(array $recipients, Human $from, string $emoteId) : void{ public function onEmote(array $recipients, Human $from, string $emoteId) : void{
$this->sendDataPacket($recipients, EmotePacket::create($from->getId(), $emoteId, "", "", EmotePacket::FLAG_SERVER)); $this->sendDataPacket($recipients, EmotePacket::create($from->getId(), $emoteId, "", "", EmotePacket::FLAG_SERVER | EmotePacket::FLAG_MUTE_ANNOUNCEMENT));
} }
} }

View File

@ -25,21 +25,17 @@ namespace pocketmine\network\mcpe\cache;
use pocketmine\crafting\CraftingManager; use pocketmine\crafting\CraftingManager;
use pocketmine\crafting\FurnaceType; use pocketmine\crafting\FurnaceType;
use pocketmine\crafting\RecipeIngredient;
use pocketmine\crafting\ShapedRecipe; use pocketmine\crafting\ShapedRecipe;
use pocketmine\crafting\ShapelessRecipe; use pocketmine\crafting\ShapelessRecipe;
use pocketmine\crafting\ShapelessRecipeType; use pocketmine\crafting\ShapelessRecipeType;
use pocketmine\item\Item;
use pocketmine\network\mcpe\convert\TypeConverter; use pocketmine\network\mcpe\convert\TypeConverter;
use pocketmine\network\mcpe\protocol\CraftingDataPacket; use pocketmine\network\mcpe\protocol\CraftingDataPacket;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
use pocketmine\network\mcpe\protocol\types\recipe\CraftingRecipeBlockName; use pocketmine\network\mcpe\protocol\types\recipe\CraftingRecipeBlockName;
use pocketmine\network\mcpe\protocol\types\recipe\FurnaceRecipe as ProtocolFurnaceRecipe; use pocketmine\network\mcpe\protocol\types\recipe\FurnaceRecipe as ProtocolFurnaceRecipe;
use pocketmine\network\mcpe\protocol\types\recipe\FurnaceRecipeBlockName; use pocketmine\network\mcpe\protocol\types\recipe\FurnaceRecipeBlockName;
use pocketmine\network\mcpe\protocol\types\recipe\IntIdMetaItemDescriptor; use pocketmine\network\mcpe\protocol\types\recipe\IntIdMetaItemDescriptor;
use pocketmine\network\mcpe\protocol\types\recipe\PotionContainerChangeRecipe as ProtocolPotionContainerChangeRecipe; use pocketmine\network\mcpe\protocol\types\recipe\PotionContainerChangeRecipe as ProtocolPotionContainerChangeRecipe;
use pocketmine\network\mcpe\protocol\types\recipe\PotionTypeRecipe as ProtocolPotionTypeRecipe; use pocketmine\network\mcpe\protocol\types\recipe\PotionTypeRecipe as ProtocolPotionTypeRecipe;
use pocketmine\network\mcpe\protocol\types\recipe\RecipeIngredient as ProtocolRecipeIngredient;
use pocketmine\network\mcpe\protocol\types\recipe\ShapedRecipe as ProtocolShapedRecipe; use pocketmine\network\mcpe\protocol\types\recipe\ShapedRecipe as ProtocolShapedRecipe;
use pocketmine\network\mcpe\protocol\types\recipe\ShapelessRecipe as ProtocolShapelessRecipe; use pocketmine\network\mcpe\protocol\types\recipe\ShapelessRecipe as ProtocolShapelessRecipe;
use pocketmine\timings\Timings; use pocketmine\timings\Timings;
@ -95,12 +91,8 @@ final class CraftingDataCache{
$recipesWithTypeIds[] = new ProtocolShapelessRecipe( $recipesWithTypeIds[] = new ProtocolShapelessRecipe(
CraftingDataPacket::ENTRY_SHAPELESS, CraftingDataPacket::ENTRY_SHAPELESS,
Binary::writeInt($index), Binary::writeInt($index),
array_map(function(RecipeIngredient $item) use ($converter) : ProtocolRecipeIngredient{ array_map($converter->coreRecipeIngredientToNet(...), $recipe->getIngredientList()),
return $converter->coreRecipeIngredientToNet($item); array_map($converter->coreItemStackToNet(...), $recipe->getResults()),
}, $recipe->getIngredientList()),
array_map(function(Item $item) use ($converter) : ItemStack{
return $converter->coreItemStackToNet($item);
}, $recipe->getResults()),
$nullUUID, $nullUUID,
$typeTag, $typeTag,
50, 50,
@ -118,9 +110,7 @@ final class CraftingDataCache{
CraftingDataPacket::ENTRY_SHAPED, CraftingDataPacket::ENTRY_SHAPED,
Binary::writeInt($index), Binary::writeInt($index),
$inputs, $inputs,
array_map(function(Item $item) use ($converter) : ItemStack{ array_map($converter->coreItemStackToNet(...), $recipe->getResults()),
return $converter->coreItemStackToNet($item);
}, $recipe->getResults()),
$nullUUID, $nullUUID,
CraftingRecipeBlockName::CRAFTING_TABLE, CraftingRecipeBlockName::CRAFTING_TABLE,
50, 50,

View File

@ -30,7 +30,7 @@ use const M_SQRT2;
final class ChunkSelector{ final class ChunkSelector{
/** /**
* @preturn \Generator|int[] * @return \Generator|int[]
* @phpstan-return \Generator<int, int, void, void> * @phpstan-return \Generator<int, int, void, void>
*/ */
public function selectChunks(int $radius, int $centerX, int $centerZ) : \Generator{ public function selectChunks(int $radius, int $centerX, int $centerZ) : \Generator{

View File

@ -1199,10 +1199,6 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
return !$this->gamemode->equals(GameMode::CREATIVE()); return !$this->gamemode->equals(GameMode::CREATIVE());
} }
public function isFireProof() : bool{
return $this->isCreative();
}
public function getDrops() : array{ public function getDrops() : array{
if($this->hasFiniteResources()){ if($this->hasFiniteResources()){
return parent::getDrops(); return parent::getDrops();
@ -1440,6 +1436,10 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$this->entityBaseTick($tickDiff); $this->entityBaseTick($tickDiff);
Timings::$entityBaseTick->stopTiming(); Timings::$entityBaseTick->stopTiming();
if($this->isCreative() && $this->fireTicks > 1){
$this->fireTicks = 1;
}
if(!$this->isSpectator() && $this->isAlive()){ if(!$this->isSpectator() && $this->isAlive()){
Timings::$playerCheckNearEntities->startTiming(); Timings::$playerCheckNearEntities->startTiming();
$this->checkNearEntities(); $this->checkNearEntities();

View File

@ -125,7 +125,10 @@ final class Process{
return count(ThreadManager::getInstance()->getAll()) + 2; //MainLogger + Main Thread return count(ThreadManager::getInstance()->getAll()) + 2; //MainLogger + Main Thread
} }
public static function kill(int $pid, bool $subprocesses) : void{ /**
* @param bool $subprocesses @deprecated
*/
public static function kill(int $pid, bool $subprocesses = false) : void{
$logger = \GlobalLogger::get(); $logger = \GlobalLogger::get();
if($logger instanceof MainLogger){ if($logger instanceof MainLogger){
$logger->syncFlushBuffer(); $logger->syncFlushBuffer();

View File

@ -121,8 +121,6 @@ trait RegistryTrait{
*/ */
private static function _registryGetAll() : array{ private static function _registryGetAll() : array{
self::checkInit(); self::checkInit();
return array_map(function(object $o) : object{ return array_map(self::preprocessMember(...), self::$members);
return self::preprocessMember($o);
}, self::$members);
} }
} }

View File

@ -42,7 +42,7 @@ class ServerKiller extends Thread{
}); });
if(time() - $start >= $this->time){ if(time() - $start >= $this->time){
echo "\nTook too long to stop, server was killed forcefully!\n"; echo "\nTook too long to stop, server was killed forcefully!\n";
@Process::kill(Process::pid(), true); @Process::kill(Process::pid());
} }
} }

View File

@ -1610,7 +1610,7 @@ class World implements ChunkManager{
* the current weather and time of day. * the current weather and time of day.
*/ */
public function getHighestAdjacentFullLightAt(int $x, int $y, int $z) : int{ public function getHighestAdjacentFullLightAt(int $x, int $y, int $z) : int{
return $this->getHighestAdjacentLight($x, $y, $z, \Closure::fromCallable([$this, 'getFullLightAt'])); return $this->getHighestAdjacentLight($x, $y, $z, $this->getFullLightAt(...));
} }
/** /**
@ -1706,7 +1706,7 @@ class World implements ChunkManager{
* Returns the highest potential level of sky light in the positions adjacent to the specified block coordinates. * Returns the highest potential level of sky light in the positions adjacent to the specified block coordinates.
*/ */
public function getHighestAdjacentPotentialBlockSkyLight(int $x, int $y, int $z) : int{ public function getHighestAdjacentPotentialBlockSkyLight(int $x, int $y, int $z) : int{
return $this->getHighestAdjacentLight($x, $y, $z, \Closure::fromCallable([$this, 'getPotentialBlockSkyLightAt'])); return $this->getHighestAdjacentLight($x, $y, $z, $this->getPotentialBlockSkyLightAt(...));
} }
/** /**
@ -1721,7 +1721,7 @@ class World implements ChunkManager{
* Returns the highest block light level available in the positions adjacent to the specified block coordinates. * Returns the highest block light level available in the positions adjacent to the specified block coordinates.
*/ */
public function getHighestAdjacentBlockLight(int $x, int $y, int $z) : int{ public function getHighestAdjacentBlockLight(int $x, int $y, int $z) : int{
return $this->getHighestAdjacentLight($x, $y, $z, \Closure::fromCallable([$this, 'getBlockLightAt'])); return $this->getHighestAdjacentLight($x, $y, $z, $this->getBlockLightAt(...));
} }
private function executeQueuedLightUpdates() : void{ private function executeQueuedLightUpdates() : void{

View File

@ -41,13 +41,13 @@ final class WorldProviderManager{
private WritableWorldProviderManagerEntry $default; private WritableWorldProviderManagerEntry $default;
public function __construct(){ public function __construct(){
$leveldb = new WritableWorldProviderManagerEntry(\Closure::fromCallable([LevelDB::class, 'isValid']), fn(string $path, \Logger $logger) => new LevelDB($path, $logger), \Closure::fromCallable([LevelDB::class, 'generate'])); $leveldb = new WritableWorldProviderManagerEntry(LevelDB::isValid(...), fn(string $path, \Logger $logger) => new LevelDB($path, $logger), LevelDB::generate(...));
$this->default = $leveldb; $this->default = $leveldb;
$this->addProvider($leveldb, "leveldb"); $this->addProvider($leveldb, "leveldb");
$this->addProvider(new ReadOnlyWorldProviderManagerEntry(\Closure::fromCallable([Anvil::class, 'isValid']), fn(string $path, \Logger $logger) => new Anvil($path, $logger)), "anvil"); $this->addProvider(new ReadOnlyWorldProviderManagerEntry(Anvil::isValid(...), fn(string $path, \Logger $logger) => new Anvil($path, $logger)), "anvil");
$this->addProvider(new ReadOnlyWorldProviderManagerEntry(\Closure::fromCallable([McRegion::class, 'isValid']), fn(string $path, \Logger $logger) => new McRegion($path, $logger)), "mcregion"); $this->addProvider(new ReadOnlyWorldProviderManagerEntry(McRegion::isValid(...), fn(string $path, \Logger $logger) => new McRegion($path, $logger)), "mcregion");
$this->addProvider(new ReadOnlyWorldProviderManagerEntry(\Closure::fromCallable([PMAnvil::class, 'isValid']), fn(string $path, \Logger $logger) => new PMAnvil($path, $logger)), "pmanvil"); $this->addProvider(new ReadOnlyWorldProviderManagerEntry(PMAnvil::isValid(...), fn(string $path, \Logger $logger) => new PMAnvil($path, $logger)), "pmanvil");
} }
/** /**

View File

@ -27,6 +27,7 @@ use pocketmine\block\Block;
use pocketmine\data\bedrock\BiomeIds; use pocketmine\data\bedrock\BiomeIds;
use pocketmine\data\bedrock\block\BlockStateDeserializeException; use pocketmine\data\bedrock\block\BlockStateDeserializeException;
use pocketmine\nbt\LittleEndianNbtSerializer; use pocketmine\nbt\LittleEndianNbtSerializer;
use pocketmine\nbt\NBT;
use pocketmine\nbt\NbtDataException; use pocketmine\nbt\NbtDataException;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\TreeRoot; use pocketmine\nbt\TreeRoot;
@ -155,7 +156,33 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
$nbt = new LittleEndianNbtSerializer(); $nbt = new LittleEndianNbtSerializer();
$palette = []; $palette = [];
$paletteSize = $bitsPerBlock === 0 ? 1 : $stream->getLInt(); if($bitsPerBlock === 0){
$paletteSize = 1;
/*
* Due to code copy-paste in a public plugin, some PM4 worlds have 0 bpb palettes with a length prefix.
* This is invalid and does not happen in vanilla.
* These palettes were accepted by PM4 despite being invalid, but PM5 considered them corrupt, causing loss
* of data. Since many users were affected by this, a workaround is therefore necessary to allow PM5 to read
* these worlds without data loss.
*
* References:
* - https://github.com/Refaltor77/CustomItemAPI/issues/68
* - https://github.com/pmmp/PocketMine-MP/issues/5911
*/
$offset = $stream->getOffset();
$byte1 = $stream->getByte();
$stream->setOffset($offset); //reset offset
if($byte1 !== NBT::TAG_Compound){ //normally the first byte would be the NBT of the blockstate
$susLength = $stream->getLInt();
if($susLength !== 1){ //make sure the data isn't complete garbage
throw new CorruptedChunkException("CustomItemAPI borked 0 bpb palette should always have a length of 1");
}
$logger->error("Unexpected palette size for 0 bpb palette");
}
}else{
$paletteSize = $stream->getLInt();
}
for($i = 0; $i < $paletteSize; ++$i){ for($i = 0; $i < $paletteSize; ++$i){
try{ try{
@ -276,6 +303,10 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
$previous = $decoded; $previous = $decoded;
if($nextIndex <= Chunk::MAX_SUBCHUNK_INDEX){ //older versions wrote additional superfluous biome palettes if($nextIndex <= Chunk::MAX_SUBCHUNK_INDEX){ //older versions wrote additional superfluous biome palettes
$result[$nextIndex++] = $decoded; $result[$nextIndex++] = $decoded;
}elseif($stream->feof()){
//not enough padding biome arrays for the given version - this is non-critical since we discard the excess anyway, but this should be logged
$logger->error("Wrong number of 3D biome palettes for this chunk version: expected $expectedCount, but got " . ($i + 1) . " - this is not a problem, but may indicate a corrupted chunk");
break;
} }
}catch(BinaryDataException $e){ }catch(BinaryDataException $e){
throw new CorruptedChunkException("Failed to deserialize biome palette $i: " . $e->getMessage(), 0, $e); throw new CorruptedChunkException("Failed to deserialize biome palette $i: " . $e->getMessage(), 0, $e);

View File

@ -78,7 +78,7 @@ final class UnsafeForeachArrayOfStringRule implements Rule{
return $type; return $type;
}); });
if($hasCastableKeyTypes && !$expectsIntKeyTypes){ if($hasCastableKeyTypes && !$expectsIntKeyTypes){
$func = \Closure::fromCallable([Utils::class, 'stringifyKeys']); $func = Utils::stringifyKeys(...);
return [ return [
RuleErrorBuilder::message(sprintf( RuleErrorBuilder::message(sprintf(
"Unsafe foreach on array with key type %s (they might be casted to int).", "Unsafe foreach on array with key type %s (they might be casted to int).",