diff --git a/src/pocketmine/world/light/BlockLightUpdate.php b/src/pocketmine/world/light/BlockLightUpdate.php index 1fbaf04c3..9be3d6a37 100644 --- a/src/pocketmine/world/light/BlockLightUpdate.php +++ b/src/pocketmine/world/light/BlockLightUpdate.php @@ -27,13 +27,8 @@ use pocketmine\block\BlockFactory; use function max; class BlockLightUpdate extends LightUpdate{ - - public function getLight(int $x, int $y, int $z) : int{ - return $this->subChunkHandler->currentSubChunk->getBlockLight($x & 0x0f, $y & 0x0f, $z & 0x0f); - } - - public function setLight(int $x, int $y, int $z, int $level) : void{ - $this->subChunkHandler->currentSubChunk->setBlockLight($x & 0x0f, $y & 0x0f, $z & 0x0f, $level); + protected function updateLightArrayRef() : void{ + $this->currentLightArray = $this->subChunkHandler->currentSubChunk->getBlockLightArray(); } public function recalculateNode(int $x, int $y, int $z) : void{ diff --git a/src/pocketmine/world/light/LightUpdate.php b/src/pocketmine/world/light/LightUpdate.php index cc3bee6af..26b0e8669 100644 --- a/src/pocketmine/world/light/LightUpdate.php +++ b/src/pocketmine/world/light/LightUpdate.php @@ -25,6 +25,7 @@ namespace pocketmine\world\light; use pocketmine\block\BlockFactory; use pocketmine\world\ChunkManager; +use pocketmine\world\format\LightArray; use pocketmine\world\utils\SubChunkIteratorManager; use pocketmine\world\World; use function max; @@ -50,17 +51,19 @@ abstract class LightUpdate{ /** @var SubChunkIteratorManager */ protected $subChunkHandler; + /** @var LightArray|null */ + protected $currentLightArray = null; + public function __construct(ChunkManager $world){ $this->world = $world; $this->removalQueue = new \SplQueue(); $this->spreadQueue = new \SplQueue(); $this->subChunkHandler = new SubChunkIteratorManager($this->world); + $this->subChunkHandler->onSubChunkChange(\Closure::fromCallable([$this, 'updateLightArrayRef'])); } - abstract protected function getLight(int $x, int $y, int $z) : int; - - abstract protected function setLight(int $x, int $y, int $z, int $level) : void; + abstract protected function updateLightArrayRef() : void; abstract public function recalculateNode(int $x, int $y, int $z) : void; @@ -74,7 +77,7 @@ abstract class LightUpdate{ [$x, $y, $z + 1], [$x, $y, $z - 1] ] as [$x1, $y1, $z1]){ - if($this->subChunkHandler->moveTo($x1, $y1, $z1, false) and ($adjacent = max($adjacent, $this->getLight($x1, $y1, $z1))) === 15){ + if($this->subChunkHandler->moveTo($x1, $y1, $z1, false) and ($adjacent = max($adjacent, $this->currentLightArray->get($x1 & 0xf, $y1 & 0xf, $z1 & 0xf))) === 15){ break; } } @@ -88,10 +91,10 @@ abstract class LightUpdate{ private function prepareNodes() : void{ foreach($this->updateNodes as $blockHash => [$x, $y, $z, $newLevel]){ if($this->subChunkHandler->moveTo($x, $y, $z, false)){ - $oldLevel = $this->getLight($x, $y, $z); + $oldLevel = $this->currentLightArray->get($x & 0xf, $y & 0xf, $z & 0xf); if($oldLevel !== $newLevel){ - $this->setLight($x, $y, $z, $newLevel); + $this->currentLightArray->set($x & 0xf, $y & 0xf, $z & 0xf, $newLevel); if($oldLevel < $newLevel){ //light increased $this->spreadVisited[$blockHash] = true; $this->spreadQueue->enqueue([$x, $y, $z]); @@ -135,7 +138,7 @@ abstract class LightUpdate{ continue; } - $newAdjacentLight = $this->getLight($x, $y, $z); + $newAdjacentLight = $this->currentLightArray->get($x & 0xf, $y & 0xf, $z & 0xf); if($newAdjacentLight <= 0){ continue; } @@ -158,10 +161,10 @@ abstract class LightUpdate{ } protected function computeRemoveLight(int $x, int $y, int $z, int $oldAdjacentLevel) : void{ - $current = $this->getLight($x, $y, $z); + $current = $this->currentLightArray->get($x & 0xf, $y & 0xf, $z & 0xf); if($current !== 0 and $current < $oldAdjacentLevel){ - $this->setLight($x, $y, $z, 0); + $this->currentLightArray->set($x & 0xf, $y & 0xf, $z & 0xf, 0); if(!isset($this->removalVisited[$index = World::blockHash($x, $y, $z)])){ $this->removalVisited[$index] = true; @@ -178,11 +181,11 @@ abstract class LightUpdate{ } protected function computeSpreadLight(int $x, int $y, int $z, int $newAdjacentLevel) : void{ - $current = $this->getLight($x, $y, $z); + $current = $this->currentLightArray->get($x & 0xf, $y & 0xf, $z & 0xf); $potentialLight = $newAdjacentLevel - BlockFactory::$lightFilter[$this->subChunkHandler->currentSubChunk->getFullBlock($x & 0x0f, $y & 0x0f, $z & 0x0f)]; if($current < $potentialLight){ - $this->setLight($x, $y, $z, $potentialLight); + $this->currentLightArray->set($x & 0xf, $y & 0xf, $z & 0xf, $potentialLight); if(!isset($this->spreadVisited[$index = World::blockHash($x, $y, $z)]) and $potentialLight > 1){ $this->spreadVisited[$index] = true; diff --git a/src/pocketmine/world/light/SkyLightUpdate.php b/src/pocketmine/world/light/SkyLightUpdate.php index 8374c862d..59ab9e98c 100644 --- a/src/pocketmine/world/light/SkyLightUpdate.php +++ b/src/pocketmine/world/light/SkyLightUpdate.php @@ -27,13 +27,8 @@ use pocketmine\block\BlockFactory; use function max; class SkyLightUpdate extends LightUpdate{ - - public function getLight(int $x, int $y, int $z) : int{ - return $this->subChunkHandler->currentSubChunk->getBlockSkyLight($x & 0x0f, $y & 0x0f, $z & 0x0f); - } - - public function setLight(int $x, int $y, int $z, int $level) : void{ - $this->subChunkHandler->currentSubChunk->setBlockSkyLight($x & 0x0f, $y & 0x0f, $z & 0x0f, $level); + protected function updateLightArrayRef() : void{ + $this->currentLightArray = $this->subChunkHandler->currentSubChunk->getBlockSkyLightArray(); } public function recalculateNode(int $x, int $y, int $z) : void{ diff --git a/src/pocketmine/world/utils/SubChunkIteratorManager.php b/src/pocketmine/world/utils/SubChunkIteratorManager.php index 55e8bbf7d..e32844553 100644 --- a/src/pocketmine/world/utils/SubChunkIteratorManager.php +++ b/src/pocketmine/world/utils/SubChunkIteratorManager.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\world\utils; +use pocketmine\utils\Utils; use pocketmine\world\ChunkManager; use pocketmine\world\format\Chunk; use pocketmine\world\format\EmptySubChunk; @@ -44,6 +45,9 @@ class SubChunkIteratorManager{ /** @var int */ protected $currentZ; + /** @var \Closure|null */ + private $onSubChunkChangeFunc = null; + public function __construct(ChunkManager $world){ $this->world = $world; } @@ -65,13 +69,22 @@ class SubChunkIteratorManager{ $this->currentSubChunk = $this->currentChunk->getSubChunk($y >> 4, $create); if($this->currentSubChunk instanceof EmptySubChunk){ + $this->currentSubChunk = null; return false; } + if($this->onSubChunkChangeFunc !== null){ + ($this->onSubChunkChangeFunc)(); + } } return true; } + public function onSubChunkChange(\Closure $callback) : void{ + Utils::validateCallableSignature(function(){}, $callback); + $this->onSubChunkChangeFunc = $callback; + } + public function invalidate() : void{ $this->currentChunk = null; $this->currentSubChunk = null;