mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-06 11:57:10 +00:00
Merge branch 'minor-next' into major-next
This commit is contained in:
commit
5ec0e0f20b
@ -1 +1 @@
|
||||
Subproject commit 46604f2f6a07e3f68a82e4f4d7efdd45629b101e
|
||||
Subproject commit ed0bc4d2afafd00f9ee92823c6b1bd66789ce4f2
|
@ -22,7 +22,7 @@
|
||||
"ext-openssl": "*",
|
||||
"ext-pcre": "*",
|
||||
"ext-phar": "*",
|
||||
"ext-pmmpthread": "^6.0.4",
|
||||
"ext-pmmpthread": "^6.0.7",
|
||||
"ext-reflection": "*",
|
||||
"ext-simplexml": "*",
|
||||
"ext-sockets": "*",
|
||||
@ -43,7 +43,7 @@
|
||||
"pocketmine/errorhandler": "^0.6.0",
|
||||
"pocketmine/locale-data": "~2.19.0",
|
||||
"pocketmine/log": "^0.4.0",
|
||||
"pocketmine/math": "^0.4.0",
|
||||
"pocketmine/math": "~1.0.0",
|
||||
"pocketmine/nbt": "^0.3.2",
|
||||
"pocketmine/raklib": "^0.15.0",
|
||||
"pocketmine/raklib-ipc": "^0.2.0",
|
||||
|
62
composer.lock
generated
62
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "ccd20e7656bc05ec2acd8e28aad9fcf2",
|
||||
"content-hash": "2d51c1adf069760587b6d36f9c4a5db3",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/json-comment",
|
||||
@ -200,16 +200,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-protocol",
|
||||
"version": "23.0.2+bedrock-1.20.10",
|
||||
"version": "23.0.3+bedrock-1.20.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockProtocol.git",
|
||||
"reference": "69a309a2dd7dcf3ec8c316385b866397e8c2cbfd"
|
||||
"reference": "e4157c7af3f91e1b08fe21be171eb73dad7029e9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/69a309a2dd7dcf3ec8c316385b866397e8c2cbfd",
|
||||
"reference": "69a309a2dd7dcf3ec8c316385b866397e8c2cbfd",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/e4157c7af3f91e1b08fe21be171eb73dad7029e9",
|
||||
"reference": "e4157c7af3f91e1b08fe21be171eb73dad7029e9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -218,8 +218,8 @@
|
||||
"php": "^8.0",
|
||||
"pocketmine/binaryutils": "^0.2.0",
|
||||
"pocketmine/color": "^0.2.0 || ^0.3.0",
|
||||
"pocketmine/math": "^0.3.0 || ^0.4.0",
|
||||
"pocketmine/nbt": "^0.3.0",
|
||||
"pocketmine/math": "^0.3.0 || ^0.4.0 || ^1.0.0",
|
||||
"pocketmine/nbt": "^0.3.0 || ^1.0.0",
|
||||
"ramsey/uuid": "^4.1"
|
||||
},
|
||||
"require-dev": {
|
||||
@ -241,9 +241,9 @@
|
||||
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
|
||||
"source": "https://github.com/pmmp/BedrockProtocol/tree/23.0.2+bedrock-1.20.10"
|
||||
"source": "https://github.com/pmmp/BedrockProtocol/tree/23.0.3+bedrock-1.20.10"
|
||||
},
|
||||
"time": "2023-07-24T15:35:36+00:00"
|
||||
"time": "2023-08-03T15:30:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/binaryutils",
|
||||
@ -480,16 +480,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/math",
|
||||
"version": "0.4.3",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/Math.git",
|
||||
"reference": "47a243d320b01c8099d65309967934c188111549"
|
||||
"reference": "dc132d93595b32e9f210d78b3c8d43c662a5edbf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/Math/zipball/47a243d320b01c8099d65309967934c188111549",
|
||||
"reference": "47a243d320b01c8099d65309967934c188111549",
|
||||
"url": "https://api.github.com/repos/pmmp/Math/zipball/dc132d93595b32e9f210d78b3c8d43c662a5edbf",
|
||||
"reference": "dc132d93595b32e9f210d78b3c8d43c662a5edbf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -498,7 +498,7 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/extension-installer": "^1.0",
|
||||
"phpstan/phpstan": "1.8.2",
|
||||
"phpstan/phpstan": "~1.10.3",
|
||||
"phpstan/phpstan-strict-rules": "^1.0",
|
||||
"phpunit/phpunit": "^8.5 || ^9.5"
|
||||
},
|
||||
@ -515,9 +515,9 @@
|
||||
"description": "PHP library containing math related code used in PocketMine-MP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/Math/issues",
|
||||
"source": "https://github.com/pmmp/Math/tree/0.4.3"
|
||||
"source": "https://github.com/pmmp/Math/tree/1.0.0"
|
||||
},
|
||||
"time": "2022-08-25T18:43:37+00:00"
|
||||
"time": "2023-08-03T12:56:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/nbt",
|
||||
@ -1541,16 +1541,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "10.1.2",
|
||||
"version": "10.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "db1497ec8dd382e82c962f7abbe0320e4882ee4e"
|
||||
"reference": "be1fe461fdc917de2a29a452ccf2657d325b443d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/db1497ec8dd382e82c962f7abbe0320e4882ee4e",
|
||||
"reference": "db1497ec8dd382e82c962f7abbe0320e4882ee4e",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/be1fe461fdc917de2a29a452ccf2657d325b443d",
|
||||
"reference": "be1fe461fdc917de2a29a452ccf2657d325b443d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1607,7 +1607,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.2"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1615,7 +1615,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-05-22T09:04:27+00:00"
|
||||
"time": "2023-07-26T13:45:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
@ -1861,16 +1861,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "10.2.6",
|
||||
"version": "10.3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "1c17815c129f133f3019cc18e8d0c8622e6d9bcd"
|
||||
"reference": "d442ce7c4104d5683c12e67e4dcb5058159e9804"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1c17815c129f133f3019cc18e8d0c8622e6d9bcd",
|
||||
"reference": "1c17815c129f133f3019cc18e8d0c8622e6d9bcd",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d442ce7c4104d5683c12e67e4dcb5058159e9804",
|
||||
"reference": "d442ce7c4104d5683c12e67e4dcb5058159e9804",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1895,7 +1895,7 @@
|
||||
"sebastian/diff": "^5.0",
|
||||
"sebastian/environment": "^6.0",
|
||||
"sebastian/exporter": "^5.0",
|
||||
"sebastian/global-state": "^6.0",
|
||||
"sebastian/global-state": "^6.0.1",
|
||||
"sebastian/object-enumerator": "^5.0",
|
||||
"sebastian/recursion-context": "^5.0",
|
||||
"sebastian/type": "^4.0",
|
||||
@ -1910,7 +1910,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "10.2-dev"
|
||||
"dev-main": "10.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -1942,7 +1942,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.2.6"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.3.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1958,7 +1958,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-07-17T12:08:28+00:00"
|
||||
"time": "2023-08-04T06:48:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
@ -2945,7 +2945,7 @@
|
||||
"ext-openssl": "*",
|
||||
"ext-pcre": "*",
|
||||
"ext-phar": "*",
|
||||
"ext-pmmpthread": "^6.0.4",
|
||||
"ext-pmmpthread": "^6.0.7",
|
||||
"ext-reflection": "*",
|
||||
"ext-simplexml": "*",
|
||||
"ext-sockets": "*",
|
||||
|
@ -11,6 +11,7 @@ includes:
|
||||
|
||||
rules:
|
||||
- pocketmine\phpstan\rules\DisallowEnumComparisonRule
|
||||
- pocketmine\phpstan\rules\DisallowForeachByReferenceRule
|
||||
- pocketmine\phpstan\rules\UnsafeForeachArrayOfStringRule
|
||||
# - pocketmine\phpstan\rules\ThreadedSupportedTypesRule
|
||||
|
||||
|
@ -120,8 +120,8 @@ namespace pocketmine {
|
||||
}
|
||||
|
||||
if(($pmmpthread_version = phpversion("pmmpthread")) !== false){
|
||||
if(version_compare($pmmpthread_version, "6.0.4") < 0 || version_compare($pmmpthread_version, "7.0.0") >= 0){
|
||||
$messages[] = "pmmpthread ^6.0.4 is required, while you have $pmmpthread_version.";
|
||||
if(version_compare($pmmpthread_version, "6.0.7") < 0 || version_compare($pmmpthread_version, "7.0.0") >= 0){
|
||||
$messages[] = "pmmpthread ^6.0.7 is required, while you have $pmmpthread_version.";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,10 +23,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\CoralType;
|
||||
use pocketmine\block\utils\CoralTypeTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\event\block\BlockDeathEvent;
|
||||
use pocketmine\item\Item;
|
||||
use function mt_rand;
|
||||
|
||||
@ -46,11 +46,7 @@ abstract class BaseCoral extends Transparent{
|
||||
|
||||
public function onScheduledUpdate() : void{
|
||||
if(!$this->dead && !$this->isCoveredWithWater()){
|
||||
$ev = new BlockDeathEvent($this, $this->setDead(true));
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
|
||||
}
|
||||
BlockEventHelper::die($this, (clone $this)->setDead(true));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,10 +23,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\block\BlockGrowEvent;
|
||||
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\item\Item;
|
||||
@ -111,12 +111,7 @@ class Cactus extends Transparent{
|
||||
}
|
||||
$b = $world->getBlockAt($this->position->x, $this->position->y + $y, $this->position->z);
|
||||
if($b->getTypeId() === BlockTypeIds::AIR){
|
||||
$ev = new BlockGrowEvent($b, VanillaBlocks::CACTUS());
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
break;
|
||||
}
|
||||
$world->setBlock($b->position, $ev->getNewState());
|
||||
BlockEventHelper::grow($b, VanillaBlocks::CACTUS(), null);
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
|
@ -23,10 +23,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\block\BlockGrowEvent;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
@ -114,16 +114,12 @@ class CaveVines extends Flowable{
|
||||
return true;
|
||||
}
|
||||
if($item instanceof Fertilizer){
|
||||
$ev = new BlockGrowEvent($this, (clone $this)
|
||||
$newState = (clone $this)
|
||||
->setBerries(true)
|
||||
->setHead(!$this->getSide(Facing::DOWN)->hasSameTypeId($this))
|
||||
);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
return false;
|
||||
->setHead(!$this->getSide(Facing::DOWN)->hasSameTypeId($this));
|
||||
if(BlockEventHelper::grow($this, $newState, $player)){
|
||||
$item->pop();
|
||||
}
|
||||
$item->pop();
|
||||
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -141,16 +137,10 @@ class CaveVines extends Flowable{
|
||||
if($world->isInWorld($growthPos->getFloorX(), $growthPos->getFloorY(), $growthPos->getFloorZ())){
|
||||
$block = $world->getBlock($growthPos);
|
||||
if($block->getTypeId() === BlockTypeIds::AIR){
|
||||
$ev = new BlockGrowEvent($block, VanillaBlocks::CAVE_VINES()
|
||||
$newState = VanillaBlocks::CAVE_VINES()
|
||||
->setAge($this->age + 1)
|
||||
->setBerries(mt_rand(1, 9) === 1)
|
||||
);
|
||||
|
||||
$ev->call();
|
||||
|
||||
if(!$ev->isCancelled()){
|
||||
$world->setBlock($growthPos, $ev->getNewState());
|
||||
}
|
||||
->setBerries(mt_rand(1, 9) === 1);
|
||||
BlockEventHelper::grow($block, $newState, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,11 +23,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\block\utils\WoodType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\event\block\BlockGrowEvent;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
@ -123,12 +123,7 @@ class CocoaBlock extends Transparent{
|
||||
if($this->age < self::MAX_AGE){
|
||||
$block = clone $this;
|
||||
$block->age++;
|
||||
$ev = new BlockGrowEvent($this, $block, $player);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
|
||||
return true;
|
||||
}
|
||||
return BlockEventHelper::grow($this, $block, $player);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -23,11 +23,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\ColoredTrait;
|
||||
use pocketmine\block\utils\DyeColor;
|
||||
use pocketmine\block\utils\Fallable;
|
||||
use pocketmine\block\utils\FallableTrait;
|
||||
use pocketmine\event\block\BlockFormEvent;
|
||||
use pocketmine\math\Facing;
|
||||
|
||||
class ConcretePowder extends Opaque implements Fallable{
|
||||
@ -43,11 +43,7 @@ class ConcretePowder extends Opaque implements Fallable{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(($water = $this->getAdjacentWater()) !== null){
|
||||
$ev = new BlockFormEvent($this, VanillaBlocks::CONCRETE()->setColor($this->color), $water);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
|
||||
}
|
||||
BlockEventHelper::form($this, VanillaBlocks::CONCRETE()->setColor($this->color), $water);
|
||||
}else{
|
||||
$this->startFalling();
|
||||
}
|
||||
|
@ -23,9 +23,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\CoralType;
|
||||
use pocketmine\block\utils\CoralTypeTrait;
|
||||
use pocketmine\event\block\BlockDeathEvent;
|
||||
use pocketmine\item\Item;
|
||||
use function mt_rand;
|
||||
|
||||
@ -55,11 +55,7 @@ final class CoralBlock extends Opaque{
|
||||
}
|
||||
}
|
||||
if(!$hasWater){
|
||||
$ev = new BlockDeathEvent($this, $this->setDead(true));
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$world->setBlock($this->position, $ev->getNewState());
|
||||
}
|
||||
BlockEventHelper::die($this, (clone $this)->setDead(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,8 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\event\block\BlockGrowEvent;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
@ -68,11 +68,7 @@ abstract class Crops extends Flowable{
|
||||
if($block->age > self::MAX_AGE){
|
||||
$block->age = self::MAX_AGE;
|
||||
}
|
||||
|
||||
$ev = new BlockGrowEvent($this, $block, $player);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
|
||||
if(BlockEventHelper::grow($this, $block, $player)){
|
||||
$item->pop();
|
||||
}
|
||||
|
||||
@ -96,11 +92,7 @@ abstract class Crops extends Flowable{
|
||||
if($this->age < self::MAX_AGE && mt_rand(0, 2) === 1){
|
||||
$block = clone $this;
|
||||
++$block->age;
|
||||
$ev = new BlockGrowEvent($this, $block);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
|
||||
}
|
||||
BlockEventHelper::grow($this, $block, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,10 +23,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\event\block\BlockBurnEvent;
|
||||
use pocketmine\event\block\BlockSpreadEvent;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\world\format\Chunk;
|
||||
use pocketmine\world\World;
|
||||
@ -225,13 +225,6 @@ class Fire extends BaseFire{
|
||||
}
|
||||
|
||||
private function spreadBlock(Block $block, Block $newState) : bool{
|
||||
$ev = new BlockSpreadEvent($block, $this, $newState);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$block->position->getWorld()->setBlock($block->position, $ev->getNewState());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return BlockEventHelper::spread($block, $newState, $this);
|
||||
}
|
||||
}
|
||||
|
@ -23,8 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\event\block\BlockMeltEvent;
|
||||
use function mt_rand;
|
||||
|
||||
class FrostedIce extends Ice{
|
||||
@ -97,11 +97,7 @@ class FrostedIce extends Ice{
|
||||
private function tryMelt() : bool{
|
||||
$world = $this->position->getWorld();
|
||||
if($this->age >= self::MAX_AGE){
|
||||
$ev = new BlockMeltEvent($this, VanillaBlocks::WATER());
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$world->setBlock($this->position, $ev->getNewState());
|
||||
}
|
||||
BlockEventHelper::melt($this, VanillaBlocks::WATER());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -23,9 +23,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\event\block\BlockSpreadEvent;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
@ -166,14 +166,7 @@ class GlowLichen extends Transparent{
|
||||
return false;
|
||||
}
|
||||
|
||||
$ev = new BlockSpreadEvent($replacedBlock, $this, $replacementBlock);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$world->setBlock($replacedBlock->getPosition(), $ev->getNewState());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return BlockEventHelper::spread($replacedBlock, $replacementBlock, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,8 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\DirtType;
|
||||
use pocketmine\event\block\BlockSpreadEvent;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Hoe;
|
||||
use pocketmine\item\Item;
|
||||
@ -58,11 +58,7 @@ class Grass extends Opaque{
|
||||
$lightAbove = $world->getFullLightAt($this->position->x, $this->position->y + 1, $this->position->z);
|
||||
if($lightAbove < 4 && $world->getBlockAt($this->position->x, $this->position->y + 1, $this->position->z)->getLightFilter() >= 2){
|
||||
//grass dies
|
||||
$ev = new BlockSpreadEvent($this, $this, VanillaBlocks::DIRT());
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$world->setBlock($this->position, $ev->getNewState(), false);
|
||||
}
|
||||
BlockEventHelper::spread($this, VanillaBlocks::DIRT(), $this);
|
||||
}elseif($lightAbove >= 9){
|
||||
//try grass spread
|
||||
for($i = 0; $i < 4; ++$i){
|
||||
@ -80,11 +76,7 @@ class Grass extends Opaque{
|
||||
continue;
|
||||
}
|
||||
|
||||
$ev = new BlockSpreadEvent($b, $this, VanillaBlocks::GRASS());
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$world->setBlock($b->position, $ev->getNewState(), false);
|
||||
}
|
||||
BlockEventHelper::spread($b, VanillaBlocks::GRASS(), $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\event\block\BlockMeltEvent;
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\item\enchantment\VanillaEnchantments;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\player\Player;
|
||||
@ -53,11 +53,7 @@ class Ice extends Transparent{
|
||||
public function onRandomTick() : void{
|
||||
$world = $this->position->getWorld();
|
||||
if($world->getHighestAdjacentBlockLight($this->position->x, $this->position->y, $this->position->z) >= 12){
|
||||
$ev = new BlockMeltEvent($this, VanillaBlocks::WATER());
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$world->setBlock($this->position, $ev->getNewState());
|
||||
}
|
||||
BlockEventHelper::melt($this, VanillaBlocks::WATER());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,11 +23,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\MinimumCostFlowCalculator;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\block\BlockFormEvent;
|
||||
use pocketmine\event\block\BlockSpreadEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
@ -363,12 +363,8 @@ abstract class Liquid extends Transparent{
|
||||
}
|
||||
|
||||
protected function liquidCollide(Block $cause, Block $result) : bool{
|
||||
$ev = new BlockFormEvent($this, $result, $cause);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$world = $this->position->getWorld();
|
||||
$world->setBlock($this->position, $ev->getNewState());
|
||||
$world->addSound($this->position->add(0.5, 0.5, 0.5), new FizzSound(2.6 + (lcg_value() - lcg_value()) * 0.8));
|
||||
if(BlockEventHelper::form($this, $result, $cause)){
|
||||
$this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), new FizzSound(2.6 + (lcg_value() - lcg_value()) * 0.8));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -113,14 +113,15 @@ class MobHead extends Flowable{
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
$collisionBox = AxisAlignedBB::one()->contract(0.25, 0, 0.25)->trim(Facing::UP, 0.5);
|
||||
return match($this->facing){
|
||||
Facing::NORTH => [$collisionBox->offset(0, 0.25, 0.25)],
|
||||
Facing::SOUTH => [$collisionBox->offset(0, 0.25, -0.25)],
|
||||
Facing::WEST => [$collisionBox->offset(0.25, 0.25, 0)],
|
||||
Facing::EAST => [$collisionBox->offset(-0.25, 0.25, 0)],
|
||||
default => [$collisionBox]
|
||||
};
|
||||
$collisionBox = AxisAlignedBB::one()
|
||||
->contract(0.25, 0, 0.25)
|
||||
->trim(Facing::UP, 0.5);
|
||||
if($this->facing !== Facing::UP){
|
||||
$collisionBox = $collisionBox
|
||||
->offsetTowards(Facing::opposite($this->facing), 0.25)
|
||||
->offsetTowards(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{
|
||||
|
@ -23,8 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\DirtType;
|
||||
use pocketmine\event\block\BlockSpreadEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use function mt_rand;
|
||||
@ -54,11 +54,7 @@ class Mycelium extends Opaque{
|
||||
$block = $world->getBlockAt($x, $y, $z);
|
||||
if($block instanceof Dirt && $block->getDirtType()->equals(DirtType::NORMAL())){
|
||||
if($block->getSide(Facing::UP) instanceof Transparent){
|
||||
$ev = new BlockSpreadEvent($block, $this, VanillaBlocks::MYCELIUM());
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$world->setBlock($block->position, $ev->getNewState());
|
||||
}
|
||||
BlockEventHelper::spread($block, VanillaBlocks::MYCELIUM(), $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,9 +23,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\event\block\BlockGrowEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
@ -76,11 +76,7 @@ class NetherWartPlant extends Flowable{
|
||||
if($this->age < self::MAX_AGE && mt_rand(0, 10) === 0){ //Still growing
|
||||
$block = clone $this;
|
||||
$block->age++;
|
||||
$ev = new BlockGrowEvent($this, $block);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
|
||||
}
|
||||
BlockEventHelper::grow($this, $block, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,10 @@ use pocketmine\item\Item;
|
||||
|
||||
class Podzol extends Opaque{
|
||||
|
||||
public function isAffectedBySilkTouch() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
VanillaBlocks::DIRT()->asItem()
|
||||
|
@ -23,11 +23,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\Fallable;
|
||||
use pocketmine\block\utils\FallableTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\event\block\BlockMeltEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
@ -105,11 +105,7 @@ class SnowLayer extends Flowable implements Fallable{
|
||||
public function onRandomTick() : void{
|
||||
$world = $this->position->getWorld();
|
||||
if($world->getBlockLightAt($this->position->x, $this->position->y, $this->position->z) >= 12){
|
||||
$ev = new BlockMeltEvent($this, VanillaBlocks::AIR());
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$world->setBlock($this->position, $ev->getNewState());
|
||||
}
|
||||
BlockEventHelper::melt($this, VanillaBlocks::AIR());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,8 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\event\block\BlockGrowEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use function array_rand;
|
||||
@ -64,11 +64,7 @@ abstract class Stem extends Crops{
|
||||
if($this->age < self::MAX_AGE){
|
||||
$block = clone $this;
|
||||
++$block->age;
|
||||
$ev = new BlockGrowEvent($this, $block);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$world->setBlock($this->position, $ev->getNewState());
|
||||
}
|
||||
BlockEventHelper::grow($this, $block, null);
|
||||
}else{
|
||||
$grow = $this->getPlant();
|
||||
foreach(Facing::HORIZONTAL as $side){
|
||||
@ -80,12 +76,7 @@ abstract class Stem extends Crops{
|
||||
$facing = Facing::HORIZONTAL[array_rand(Facing::HORIZONTAL)];
|
||||
$side = $this->getSide($facing);
|
||||
if($side->getTypeId() === BlockTypeIds::AIR && $side->getSide(Facing::DOWN)->hasTypeTag(BlockTypeTags::DIRT)){
|
||||
$ev = new BlockGrowEvent($side, $grow);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$world->setBlock($this->position, $this->setFacing($facing));
|
||||
$world->setBlock($side->position, $ev->getNewState());
|
||||
}
|
||||
BlockEventHelper::grow($side, $grow, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,8 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\event\block\BlockGrowEvent;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
@ -60,13 +60,11 @@ class Sugarcane extends Flowable{
|
||||
}
|
||||
$b = $world->getBlockAt($pos->x, $pos->y + $y, $pos->z);
|
||||
if($b->getTypeId() === BlockTypeIds::AIR){
|
||||
$ev = new BlockGrowEvent($b, VanillaBlocks::SUGARCANE(), $player);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
if(BlockEventHelper::grow($b, VanillaBlocks::SUGARCANE(), $player)){
|
||||
$grew = true;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
$world->setBlock($b->position, $ev->getNewState());
|
||||
$grew = true;
|
||||
}elseif(!$b->hasSameTypeId($this)){
|
||||
break;
|
||||
}
|
||||
|
@ -23,11 +23,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\Living;
|
||||
use pocketmine\event\block\BlockGrowEvent;
|
||||
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
@ -87,15 +87,9 @@ class SweetBerryBush extends Flowable{
|
||||
if($this->age < self::STAGE_MATURE && $item instanceof Fertilizer){
|
||||
$block = clone $this;
|
||||
$block->age++;
|
||||
|
||||
$ev = new BlockGrowEvent($this, $block, $player);
|
||||
$ev->call();
|
||||
|
||||
if(!$ev->isCancelled()){
|
||||
$world->setBlock($this->position, $ev->getNewState());
|
||||
if(BlockEventHelper::grow($this, $block, $player)){
|
||||
$item->pop();
|
||||
}
|
||||
|
||||
}elseif(($dropAmount = $this->getBerryDropAmount()) > 0){
|
||||
$world->setBlock($this->position, $this->setAge(self::STAGE_BUSH_NO_BERRIES));
|
||||
$world->dropItem($this->position, $this->asItem()->setCount($dropAmount));
|
||||
@ -133,11 +127,7 @@ class SweetBerryBush extends Flowable{
|
||||
if($this->age < self::STAGE_MATURE && mt_rand(0, 2) === 1){
|
||||
$block = clone $this;
|
||||
++$block->age;
|
||||
$ev = new BlockGrowEvent($this, $block);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
|
||||
}
|
||||
BlockEventHelper::grow($this, $block, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
115
src/block/utils/BlockEventHelper.php
Normal file
115
src/block/utils/BlockEventHelper.php
Normal file
@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\event\block\BlockDeathEvent;
|
||||
use pocketmine\event\block\BlockFormEvent;
|
||||
use pocketmine\event\block\BlockGrowEvent;
|
||||
use pocketmine\event\block\BlockMeltEvent;
|
||||
use pocketmine\event\block\BlockSpreadEvent;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
/**
|
||||
* Helper class to call block changing events and apply the results to the world.
|
||||
* TODO: try to further reduce the amount of code duplication here - while this is much better than before, it's still
|
||||
* very repetitive.
|
||||
*/
|
||||
final class BlockEventHelper{
|
||||
|
||||
public static function grow(Block $oldState, Block $newState, ?Player $causingPlayer) : bool{
|
||||
if(BlockGrowEvent::hasHandlers()){
|
||||
$ev = new BlockGrowEvent($oldState, $newState, $causingPlayer);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
return false;
|
||||
}
|
||||
$newState = $ev->getNewState();
|
||||
}
|
||||
|
||||
$position = $oldState->getPosition();
|
||||
$position->getWorld()->setBlock($position, $newState);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function spread(Block $oldState, Block $newState, Block $source) : bool{
|
||||
if(BlockSpreadEvent::hasHandlers()){
|
||||
$ev = new BlockSpreadEvent($oldState, $source, $newState);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
return false;
|
||||
}
|
||||
$newState = $ev->getNewState();
|
||||
}
|
||||
|
||||
$position = $oldState->getPosition();
|
||||
$position->getWorld()->setBlock($position, $newState);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function form(Block $oldState, Block $newState, Block $cause) : bool{
|
||||
if(BlockFormEvent::hasHandlers()){
|
||||
$ev = new BlockFormEvent($oldState, $newState, $cause);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
return false;
|
||||
}
|
||||
$newState = $ev->getNewState();
|
||||
}
|
||||
|
||||
$position = $oldState->getPosition();
|
||||
$position->getWorld()->setBlock($position, $newState);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function melt(Block $oldState, Block $newState) : bool{
|
||||
if(BlockMeltEvent::hasHandlers()){
|
||||
$ev = new BlockMeltEvent($oldState, $newState);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
return false;
|
||||
}
|
||||
$newState = $ev->getNewState();
|
||||
}
|
||||
|
||||
$position = $oldState->getPosition();
|
||||
$position->getWorld()->setBlock($position, $newState);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function die(Block $oldState, Block $newState) : bool{
|
||||
if(BlockDeathEvent::hasHandlers()){
|
||||
$ev = new BlockDeathEvent($oldState, $newState);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
return false;
|
||||
}
|
||||
$newState = $ev->getNewState();
|
||||
}
|
||||
|
||||
$position = $oldState->getPosition();
|
||||
$position->getWorld()->setBlock($position, $newState);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\event;
|
||||
|
||||
use pocketmine\timings\Timings;
|
||||
use function count;
|
||||
use function get_class;
|
||||
|
||||
abstract class Event{
|
||||
@ -54,11 +55,11 @@ abstract class Event{
|
||||
$timings = Timings::getEventTimings($this);
|
||||
$timings->startTiming();
|
||||
|
||||
$handlerList = HandlerListManager::global()->getListFor(get_class($this));
|
||||
$handlers = HandlerListManager::global()->getHandlersFor(static::class);
|
||||
|
||||
++self::$eventCallDepth;
|
||||
try{
|
||||
foreach($handlerList->getListenerList() as $registration){
|
||||
foreach($handlers as $registration){
|
||||
$registration->callEvent($this);
|
||||
}
|
||||
}finally{
|
||||
@ -66,4 +67,14 @@ abstract class Event{
|
||||
$timings->stopTiming();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the current class context has any registered global handlers.
|
||||
* This can be used in hot code paths to avoid unnecessary event object creation.
|
||||
*
|
||||
* Usage: SomeEventClass::hasHandlers()
|
||||
*/
|
||||
public static function hasHandlers() : bool{
|
||||
return count(HandlerListManager::global()->getHandlersFor(static::class)) > 0;
|
||||
}
|
||||
}
|
||||
|
@ -33,8 +33,6 @@ class HandlerList{
|
||||
/** @var RegisteredListener[][] */
|
||||
private array $handlerSlots = [];
|
||||
|
||||
private RegisteredListenerCache $handlerCache;
|
||||
|
||||
/** @var RegisteredListenerCache[] */
|
||||
private array $affectedHandlerCaches = [];
|
||||
|
||||
@ -44,9 +42,9 @@ class HandlerList{
|
||||
*/
|
||||
public function __construct(
|
||||
private string $class,
|
||||
private ?HandlerList $parentList
|
||||
private ?HandlerList $parentList,
|
||||
private RegisteredListenerCache $handlerCache = new RegisteredListenerCache()
|
||||
){
|
||||
$this->handlerCache = new RegisteredListenerCache();
|
||||
for($list = $this; $list !== null; $list = $list->parentList){
|
||||
$list->affectedHandlerCaches[spl_object_id($this->handlerCache)] = $this->handlerCache;
|
||||
}
|
||||
|
@ -36,6 +36,11 @@ class HandlerListManager{
|
||||
|
||||
/** @var HandlerList[] classname => HandlerList */
|
||||
private array $allLists = [];
|
||||
/**
|
||||
* @var RegisteredListenerCache[] event class name => cache
|
||||
* @phpstan-var array<class-string<Event>, RegisteredListenerCache>
|
||||
*/
|
||||
private array $handlerCaches = [];
|
||||
|
||||
/**
|
||||
* Unregisters all the listeners
|
||||
@ -98,7 +103,25 @@ class HandlerListManager{
|
||||
}
|
||||
|
||||
$parent = self::resolveNearestHandleableParent($class);
|
||||
return $this->allLists[$event] = new HandlerList($event, $parent !== null ? $this->getListFor($parent->getName()) : null);
|
||||
$cache = new RegisteredListenerCache();
|
||||
$this->handlerCaches[$event] = $cache;
|
||||
return $this->allLists[$event] = new HandlerList(
|
||||
$event,
|
||||
parentList: $parent !== null ? $this->getListFor($parent->getName()) : null,
|
||||
handlerCache: $cache
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-template TEvent of Event
|
||||
* @phpstan-param class-string<TEvent> $event
|
||||
*
|
||||
* @return RegisteredListener[]
|
||||
*/
|
||||
public function getHandlersFor(string $event) : array{
|
||||
$cache = $this->handlerCaches[$event] ?? null;
|
||||
//getListFor() will populate the cache for the next call
|
||||
return $cache?->list ?? $this->getListFor($event)->getListenerList();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -406,10 +406,12 @@ class NetworkSession{
|
||||
$timings->startTiming();
|
||||
|
||||
try{
|
||||
$ev = new DataPacketDecodeEvent($this, $packet->pid(), $buffer);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
return;
|
||||
if(DataPacketDecodeEvent::hasHandlers()){
|
||||
$ev = new DataPacketDecodeEvent($this, $packet->pid(), $buffer);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$decodeTimings = Timings::getDecodeDataPacketTimings($packet);
|
||||
@ -429,19 +431,22 @@ class NetworkSession{
|
||||
$decodeTimings->stopTiming();
|
||||
}
|
||||
|
||||
$ev = new DataPacketReceiveEvent($this, $packet);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$handlerTimings = Timings::getHandleDataPacketTimings($packet);
|
||||
$handlerTimings->startTiming();
|
||||
try{
|
||||
if($this->handler === null || !$packet->handle($this->handler)){
|
||||
$this->logger->debug("Unhandled " . $packet->getName() . ": " . base64_encode($stream->getBuffer()));
|
||||
}
|
||||
}finally{
|
||||
$handlerTimings->stopTiming();
|
||||
if(DataPacketReceiveEvent::hasHandlers()){
|
||||
$ev = new DataPacketReceiveEvent($this, $packet);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
return;
|
||||
}
|
||||
}
|
||||
$handlerTimings = Timings::getHandleDataPacketTimings($packet);
|
||||
$handlerTimings->startTiming();
|
||||
try{
|
||||
if($this->handler === null || !$packet->handle($this->handler)){
|
||||
$this->logger->debug("Unhandled " . $packet->getName() . ": " . base64_encode($stream->getBuffer()));
|
||||
}
|
||||
}finally{
|
||||
$handlerTimings->stopTiming();
|
||||
}
|
||||
}finally{
|
||||
$timings->stopTiming();
|
||||
}
|
||||
@ -459,12 +464,16 @@ class NetworkSession{
|
||||
$timings = Timings::getSendDataPacketTimings($packet);
|
||||
$timings->startTiming();
|
||||
try{
|
||||
$ev = new DataPacketSendEvent([$this], [$packet]);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
return false;
|
||||
if(DataPacketSendEvent::hasHandlers()){
|
||||
$ev = new DataPacketSendEvent([$this], [$packet]);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
return false;
|
||||
}
|
||||
$packets = $ev->getPackets();
|
||||
}else{
|
||||
$packets = [$packet];
|
||||
}
|
||||
$packets = $ev->getPackets();
|
||||
|
||||
foreach($packets as $evPacket){
|
||||
$this->addToSendBuffer(self::encodePacketTimed(PacketSerializer::encoder($this->packetSerializerContext), $evPacket));
|
||||
|
@ -44,12 +44,14 @@ final class StandardPacketBroadcaster implements PacketBroadcaster{
|
||||
public function broadcastPackets(array $recipients, array $packets) : void{
|
||||
//TODO: this shouldn't really be called here, since the broadcaster might be replaced by an alternative
|
||||
//implementation that doesn't fire events
|
||||
$ev = new DataPacketSendEvent($recipients, $packets);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
return;
|
||||
if(DataPacketSendEvent::hasHandlers()){
|
||||
$ev = new DataPacketSendEvent($recipients, $packets);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
return;
|
||||
}
|
||||
$packets = $ev->getPackets();
|
||||
}
|
||||
$packets = $ev->getPackets();
|
||||
|
||||
$compressors = [];
|
||||
|
||||
|
@ -85,6 +85,7 @@ class RakLibServer extends Thread{
|
||||
gc_enable();
|
||||
ini_set("display_errors", '1');
|
||||
ini_set("display_startup_errors", '1');
|
||||
\GlobalLogger::set($this->logger);
|
||||
|
||||
$socket = new ServerSocket($this->address->deserialize());
|
||||
$manager = new Server(
|
||||
@ -107,11 +108,6 @@ class RakLibServer extends Thread{
|
||||
$manager->waitShutdown();
|
||||
}
|
||||
|
||||
protected function onUncaughtException(\Throwable $e) : void{
|
||||
parent::onUncaughtException($e);
|
||||
$this->logger->logException($e);
|
||||
}
|
||||
|
||||
public function getThreadName() : string{
|
||||
return "RakLib";
|
||||
}
|
||||
|
@ -81,9 +81,9 @@ class PermissionManager{
|
||||
}
|
||||
|
||||
public function unsubscribeFromAllPermissions(PermissibleInternal $permissible) : void{
|
||||
foreach($this->permSubs as $permission => &$subs){
|
||||
unset($subs[spl_object_id($permissible)]);
|
||||
if(count($subs) === 0){
|
||||
foreach($this->permSubs as $permission => $subs){
|
||||
unset($this->permSubs[$permission][spl_object_id($permissible)]);
|
||||
if(count($this->permSubs[$permission]) === 0){
|
||||
unset($this->permSubs[$permission]);
|
||||
}
|
||||
}
|
||||
|
@ -154,6 +154,13 @@ class ResourcePackManager{
|
||||
return $this->serverForceResources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether players must accept resource packs in order to join.
|
||||
*/
|
||||
public function setResourcePacksRequired(bool $value) : void{
|
||||
$this->serverForceResources = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of resource packs in use, sorted in order of priority.
|
||||
* @return ResourcePack[]
|
||||
|
@ -69,11 +69,6 @@ class AsyncWorker extends Worker{
|
||||
$this->saveToThreadStore(self::TLS_KEY_NOTIFIER, $this->sleeperEntry->createNotifier());
|
||||
}
|
||||
|
||||
protected function onUncaughtException(\Throwable $e) : void{
|
||||
parent::onUncaughtException($e);
|
||||
$this->logger->logException($e);
|
||||
}
|
||||
|
||||
public function getLogger() : ThreadSafeLogger{
|
||||
return $this->logger;
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ use pocketmine\errorhandler\ErrorToExceptionHandler;
|
||||
use pocketmine\Server;
|
||||
use function error_get_last;
|
||||
use function error_reporting;
|
||||
use function implode;
|
||||
use function register_shutdown_function;
|
||||
use function set_exception_handler;
|
||||
|
||||
@ -115,6 +116,7 @@ trait CommonThreadPartsTrait{
|
||||
protected function onUncaughtException(\Throwable $e) : void{
|
||||
$this->synchronized(function() use ($e) : void{
|
||||
$this->crashInfo = ThreadCrashInfo::fromThrowable($e, $this->getThreadName());
|
||||
\GlobalLogger::get()->logException($e);
|
||||
});
|
||||
}
|
||||
|
||||
@ -124,15 +126,26 @@ trait CommonThreadPartsTrait{
|
||||
*/
|
||||
protected function onShutdown() : void{
|
||||
$this->synchronized(function() : void{
|
||||
if(!$this->isKilled && $this->crashInfo === null){
|
||||
if($this->isTerminated() && $this->crashInfo === null){
|
||||
$last = error_get_last();
|
||||
if($last !== null){
|
||||
//fatal error
|
||||
$this->crashInfo = ThreadCrashInfo::fromLastErrorInfo($last, $this->getThreadName());
|
||||
$crashInfo = ThreadCrashInfo::fromLastErrorInfo($last, $this->getThreadName());
|
||||
}else{
|
||||
//probably misused exit()
|
||||
$this->crashInfo = ThreadCrashInfo::fromThrowable(new \RuntimeException("Thread crashed without an error - perhaps exit() was called?"), $this->getThreadName());
|
||||
$crashInfo = ThreadCrashInfo::fromThrowable(new \RuntimeException("Thread crashed without an error - perhaps exit() was called?"), $this->getThreadName());
|
||||
}
|
||||
$this->crashInfo = $crashInfo;
|
||||
|
||||
$lines = [];
|
||||
//mimic exception printed format
|
||||
$lines[] = "Fatal error: " . $crashInfo->makePrettyMessage();
|
||||
$lines[] = "--- Stack trace ---";
|
||||
foreach($crashInfo->getTrace() as $frame){
|
||||
$lines[] = " " . $frame->getPrintableFrame();
|
||||
}
|
||||
$lines[] = "--- End of fatal error information ---";
|
||||
\GlobalLogger::get()->critical(implode("\n", $lines));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -200,6 +200,11 @@ class World implements ChunkManager{
|
||||
* @phpstan-var array<ChunkPosHash, array<ChunkBlockPosHash, Block>>
|
||||
*/
|
||||
private array $blockCache = [];
|
||||
/**
|
||||
* @var AxisAlignedBB[][][] chunkHash => [relativeBlockHash => AxisAlignedBB[]]
|
||||
* @phpstan-var array<ChunkPosHash, array<ChunkBlockPosHash, list<AxisAlignedBB>>>
|
||||
*/
|
||||
private array $blockCollisionBoxCache = [];
|
||||
|
||||
private int $sendTimeTicker = 0;
|
||||
|
||||
@ -646,6 +651,7 @@ class World implements ChunkManager{
|
||||
|
||||
$this->provider->close();
|
||||
$this->blockCache = [];
|
||||
$this->blockCollisionBoxCache = [];
|
||||
|
||||
$this->unloaded = true;
|
||||
}
|
||||
@ -1117,6 +1123,7 @@ class World implements ChunkManager{
|
||||
public function clearCache(bool $force = false) : void{
|
||||
if($force){
|
||||
$this->blockCache = [];
|
||||
$this->blockCollisionBoxCache = [];
|
||||
}else{
|
||||
$count = 0;
|
||||
foreach($this->blockCache as $list){
|
||||
@ -1126,6 +1133,16 @@ class World implements ChunkManager{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
foreach($this->blockCollisionBoxCache as $list){
|
||||
$count += count($list);
|
||||
if($count > 2048){
|
||||
//TODO: Is this really the best logic?
|
||||
$this->blockCollisionBoxCache = [];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1491,25 +1508,53 @@ class World implements ChunkManager{
|
||||
return $collides;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all block AABBs which overlap the full block area at the given coordinates.
|
||||
* This checks a padding of 1 block around the coordinates to account for oversized AABBs of blocks like fences.
|
||||
* Larger AABBs (>= 2 blocks on any axis) are not accounted for.
|
||||
*
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
private function getCollisionBoxesForCell(int $x, int $y, int $z) : array{
|
||||
$block = $this->getBlockAt($x, $y, $z);
|
||||
$boxes = $block->getCollisionBoxes();
|
||||
|
||||
$cellBB = AxisAlignedBB::one()->offset($x, $y, $z);
|
||||
foreach(Facing::ALL as $facing){
|
||||
$extraBoxes = $block->getSide($facing)->getCollisionBoxes();
|
||||
foreach($extraBoxes as $extraBox){
|
||||
if($extraBox->intersectsWith($cellBB)){
|
||||
$boxes[] = $extraBox;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $boxes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
* @phpstan-return list<AxisAlignedBB>
|
||||
*/
|
||||
public function getCollisionBoxes(Entity $entity, AxisAlignedBB $bb, bool $entities = true) : array{
|
||||
$minX = (int) floor($bb->minX - 1);
|
||||
$minY = (int) floor($bb->minY - 1);
|
||||
$minZ = (int) floor($bb->minZ - 1);
|
||||
$maxX = (int) floor($bb->maxX + 1);
|
||||
$maxY = (int) floor($bb->maxY + 1);
|
||||
$maxZ = (int) floor($bb->maxZ + 1);
|
||||
$minX = (int) floor($bb->minX);
|
||||
$minY = (int) floor($bb->minY);
|
||||
$minZ = (int) floor($bb->minZ);
|
||||
$maxX = (int) floor($bb->maxX);
|
||||
$maxY = (int) floor($bb->maxY);
|
||||
$maxZ = (int) floor($bb->maxZ);
|
||||
|
||||
$collides = [];
|
||||
|
||||
for($z = $minZ; $z <= $maxZ; ++$z){
|
||||
for($x = $minX; $x <= $maxX; ++$x){
|
||||
$chunkPosHash = World::chunkHash($x >> Chunk::COORD_BIT_SIZE, $z >> Chunk::COORD_BIT_SIZE);
|
||||
for($y = $minY; $y <= $maxY; ++$y){
|
||||
$block = $this->getBlockAt($x, $y, $z);
|
||||
foreach($block->getCollisionBoxes() as $blockBB){
|
||||
$relativeBlockHash = World::chunkBlockHash($x, $y, $z);
|
||||
|
||||
$boxes = $this->blockCollisionBoxCache[$chunkPosHash][$relativeBlockHash] ??= $this->getCollisionBoxesForCell($x, $y, $z);
|
||||
|
||||
foreach($boxes as $blockBB){
|
||||
if($blockBB->intersectsWith($bb)){
|
||||
$collides[] = $blockBB;
|
||||
}
|
||||
@ -1682,14 +1727,10 @@ class World implements ChunkManager{
|
||||
*/
|
||||
private function getHighestAdjacentLight(int $x, int $y, int $z, \Closure $lightGetter) : int{
|
||||
$max = 0;
|
||||
foreach([
|
||||
[$x + 1, $y, $z],
|
||||
[$x - 1, $y, $z],
|
||||
[$x, $y + 1, $z],
|
||||
[$x, $y - 1, $z],
|
||||
[$x, $y, $z + 1],
|
||||
[$x, $y, $z - 1]
|
||||
] as [$x1, $y1, $z1]){
|
||||
foreach(Facing::OFFSET as [$offsetX, $offsetY, $offsetZ]){
|
||||
$x1 = $x + $offsetX;
|
||||
$y1 = $y + $offsetY;
|
||||
$z1 = $z + $offsetZ;
|
||||
if(
|
||||
!$this->isInWorld($x1, $y1, $z1) ||
|
||||
($chunk = $this->getChunk($x1 >> Chunk::COORD_BIT_SIZE, $z1 >> Chunk::COORD_BIT_SIZE)) === null ||
|
||||
@ -1858,6 +1899,14 @@ class World implements ChunkManager{
|
||||
$relativeBlockHash = World::chunkBlockHash($x, $y, $z);
|
||||
|
||||
unset($this->blockCache[$chunkHash][$relativeBlockHash]);
|
||||
unset($this->blockCollisionBoxCache[$chunkHash][$relativeBlockHash]);
|
||||
//blocks like fences have collision boxes that reach into neighbouring blocks, so we need to invalidate the
|
||||
//caches for those blocks as well
|
||||
foreach(Facing::OFFSET as [$offsetX, $offsetY, $offsetZ]){
|
||||
$sideChunkPosHash = World::chunkHash(($x + $offsetX) >> Chunk::COORD_BIT_SIZE, ($z + $offsetZ) >> Chunk::COORD_BIT_SIZE);
|
||||
$sideChunkBlockHash = World::chunkBlockHash($x + $offsetX, $y + $offsetY, $z + $offsetZ);
|
||||
unset($this->blockCollisionBoxCache[$sideChunkPosHash][$sideChunkBlockHash]);
|
||||
}
|
||||
|
||||
if(!isset($this->changedBlocks[$chunkHash])){
|
||||
$this->changedBlocks[$chunkHash] = [];
|
||||
@ -2454,6 +2503,7 @@ class World implements ChunkManager{
|
||||
$this->chunks[$chunkHash] = $chunk;
|
||||
|
||||
unset($this->blockCache[$chunkHash]);
|
||||
unset($this->blockCollisionBoxCache[$chunkHash]);
|
||||
unset($this->changedBlocks[$chunkHash]);
|
||||
$chunk->setTerrainDirty();
|
||||
$this->markTickingChunkForRecheck($chunkX, $chunkZ); //this replacement chunk may not meet the conditions for ticking
|
||||
@ -2733,6 +2783,7 @@ class World implements ChunkManager{
|
||||
}
|
||||
$this->chunks[$chunkHash] = $chunk;
|
||||
unset($this->blockCache[$chunkHash]);
|
||||
unset($this->blockCollisionBoxCache[$chunkHash]);
|
||||
|
||||
$this->initChunk($x, $z, $chunkData);
|
||||
|
||||
@ -2887,6 +2938,7 @@ class World implements ChunkManager{
|
||||
|
||||
unset($this->chunks[$chunkHash]);
|
||||
unset($this->blockCache[$chunkHash]);
|
||||
unset($this->blockCollisionBoxCache[$chunkHash]);
|
||||
unset($this->changedBlocks[$chunkHash]);
|
||||
unset($this->registeredTickingChunks[$chunkHash]);
|
||||
$this->markTickingChunkForRecheck($x, $z);
|
||||
@ -2951,7 +3003,7 @@ class World implements ChunkManager{
|
||||
* @throws WorldException if the terrain is not generated
|
||||
*/
|
||||
public function getSafeSpawn(?Vector3 $spawn = null) : Position{
|
||||
if(!($spawn instanceof Vector3) || $spawn->y < 1){
|
||||
if(!($spawn instanceof Vector3) || $spawn->y <= $this->minY){
|
||||
$spawn = $this->getSpawnLocation();
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\world\light;
|
||||
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\world\format\LightArray;
|
||||
use pocketmine\world\format\SubChunk;
|
||||
use pocketmine\world\utils\SubChunkExplorer;
|
||||
@ -33,15 +34,6 @@ use function max;
|
||||
|
||||
//TODO: make light updates asynchronous
|
||||
abstract class LightUpdate{
|
||||
private const ADJACENTS = [
|
||||
[ 1, 0, 0],
|
||||
[-1, 0, 0],
|
||||
[ 0, 1, 0],
|
||||
[ 0, -1, 0],
|
||||
[ 0, 0, 1],
|
||||
[ 0, 0, -1]
|
||||
];
|
||||
|
||||
public const BASE_LIGHT_FILTER = 1;
|
||||
|
||||
/**
|
||||
@ -78,7 +70,7 @@ abstract class LightUpdate{
|
||||
|
||||
protected function getHighestAdjacentLight(int $x, int $y, int $z) : int{
|
||||
$adjacent = 0;
|
||||
foreach(self::ADJACENTS as [$ox, $oy, $oz]){
|
||||
foreach(Facing::OFFSET as [$ox, $oy, $oz]){
|
||||
if(($adjacent = max($adjacent, $this->getEffectiveLight($x + $ox, $y + $oy, $z + $oz))) === 15){
|
||||
break;
|
||||
}
|
||||
@ -123,7 +115,7 @@ abstract class LightUpdate{
|
||||
$touched++;
|
||||
[$x, $y, $z, $oldAdjacentLight] = $context->removalQueue->dequeue();
|
||||
|
||||
foreach(self::ADJACENTS as [$ox, $oy, $oz]){
|
||||
foreach(Facing::OFFSET as [$ox, $oy, $oz]){
|
||||
$cx = $x + $ox;
|
||||
$cy = $y + $oy;
|
||||
$cz = $z + $oz;
|
||||
@ -163,7 +155,7 @@ abstract class LightUpdate{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach(self::ADJACENTS as [$ox, $oy, $oz]){
|
||||
foreach(Facing::OFFSET as [$ox, $oy, $oz]){
|
||||
$cx = $x + $ox;
|
||||
$cy = $y + $oy;
|
||||
$cz = $z + $oz;
|
||||
|
53
tests/phpstan/rules/DisallowForeachByReferenceRule.php
Normal file
53
tests/phpstan/rules/DisallowForeachByReferenceRule.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\phpstan\rules;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\Foreach_;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Rules\Rule;
|
||||
use PHPStan\Rules\RuleErrorBuilder;
|
||||
|
||||
/**
|
||||
* @phpstan-implements Rule<Foreach_>
|
||||
*/
|
||||
final class DisallowForeachByReferenceRule implements Rule{
|
||||
|
||||
public function getNodeType() : string{
|
||||
return Foreach_::class;
|
||||
}
|
||||
|
||||
public function processNode(Node $node, Scope $scope) : array{
|
||||
/** @var Foreach_ $node */
|
||||
if($node->byRef){
|
||||
return [
|
||||
RuleErrorBuilder::message("Foreach by-reference is not allowed, because it has surprising behaviour.")
|
||||
->tip("If the value variable is used outside of the foreach construct (e.g. in a second foreach), the iterable's contents will be unexpectedly altered.")
|
||||
->build()
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\RuntimeBlockStateRegistry;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\Utils;
|
||||
|
||||
require dirname(__DIR__, 3) . '/vendor/autoload.php';
|
||||
|
||||
@ -91,8 +92,9 @@ foreach($new as $stateId => $name){
|
||||
$newTable[$name][] = $stateId;
|
||||
}
|
||||
ksort($newTable, SORT_STRING);
|
||||
foreach($newTable as &$stateIds){
|
||||
foreach(Utils::stringifyKeys($newTable) as $name => $stateIds){
|
||||
sort($stateIds, SORT_NUMERIC);
|
||||
$newTable[$name] = $stateIds;
|
||||
}
|
||||
|
||||
file_put_contents(__DIR__ . '/block_factory_consistency_check.json', json_encode(
|
||||
|
Loading…
x
Reference in New Issue
Block a user