LightUpdate: remove premature optimisation which breaks when mass-update lighting is used

when setBlockSkyLightArray/setBlockLightArray was used, currentLightArray would retain a reference to the old light array, which would cause false readings if SubChunkExplorer didn't move away from that subchunk and back.
This causes a small degradation of performance, but I think it can be implemented differently anyway.
This also fixes #3816.
This commit is contained in:
Dylan K. Taylor 2020-10-27 18:01:31 +00:00
parent 05ab75b5ce
commit 0ecd68e4a7
3 changed files with 17 additions and 16 deletions

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\world\light; namespace pocketmine\world\light;
use pocketmine\world\format\LightArray;
use pocketmine\world\utils\SubChunkExplorer; use pocketmine\world\utils\SubChunkExplorer;
use pocketmine\world\utils\SubChunkExplorerStatus; use pocketmine\world\utils\SubChunkExplorerStatus;
use function max; use function max;
@ -46,8 +47,8 @@ class BlockLightUpdate extends LightUpdate{
$this->lightEmitters = $lightEmitters; $this->lightEmitters = $lightEmitters;
} }
protected function updateLightArrayRef() : void{ protected function getCurrentLightArray() : LightArray{
$this->currentLightArray = $this->subChunkExplorer->currentSubChunk->getBlockLightArray(); return $this->subChunkExplorer->currentSubChunk->getBlockLightArray();
} }
public function recalculateNode(int $x, int $y, int $z) : void{ public function recalculateNode(int $x, int $y, int $z) : void{

View File

@ -47,9 +47,6 @@ abstract class LightUpdate{
/** @var SubChunkExplorer */ /** @var SubChunkExplorer */
protected $subChunkExplorer; protected $subChunkExplorer;
/** @var LightArray|null */
protected $currentLightArray = null;
/** /**
* @param \SplFixedArray|int[] $lightFilters * @param \SplFixedArray|int[] $lightFilters
* @phpstan-param \SplFixedArray<int> $lightFilters * @phpstan-param \SplFixedArray<int> $lightFilters
@ -58,16 +55,15 @@ abstract class LightUpdate{
$this->lightFilters = $lightFilters; $this->lightFilters = $lightFilters;
$this->subChunkExplorer = $subChunkExplorer; $this->subChunkExplorer = $subChunkExplorer;
$this->subChunkExplorer->onSubChunkChange(\Closure::fromCallable([$this, 'updateLightArrayRef']));
} }
abstract protected function updateLightArrayRef() : void; abstract protected function getCurrentLightArray() : LightArray;
abstract public function recalculateNode(int $x, int $y, int $z) : void; abstract public function recalculateNode(int $x, int $y, int $z) : void;
protected function getEffectiveLight(int $x, int $y, int $z) : int{ protected function getEffectiveLight(int $x, int $y, int $z) : int{
if($this->subChunkExplorer->moveTo($x, $y, $z, false) !== SubChunkExplorerStatus::INVALID){ if($this->subChunkExplorer->moveTo($x, $y, $z, false) !== SubChunkExplorerStatus::INVALID){
return $this->currentLightArray->get($x & 0xf, $y & 0xf, $z & 0xf); return $this->getCurrentLightArray()->get($x & 0xf, $y & 0xf, $z & 0xf);
} }
return 0; return 0;
} }
@ -97,10 +93,11 @@ abstract class LightUpdate{
$context = new LightPropagationContext(); $context = new LightPropagationContext();
foreach($this->updateNodes as $blockHash => [$x, $y, $z, $newLevel]){ foreach($this->updateNodes as $blockHash => [$x, $y, $z, $newLevel]){
if($this->subChunkExplorer->moveTo($x, $y, $z, false) !== SubChunkExplorerStatus::INVALID){ if($this->subChunkExplorer->moveTo($x, $y, $z, false) !== SubChunkExplorerStatus::INVALID){
$oldLevel = $this->currentLightArray->get($x & 0xf, $y & 0xf, $z & 0xf); $lightArray = $this->getCurrentLightArray();
$oldLevel = $lightArray->get($x & 0xf, $y & 0xf, $z & 0xf);
if($oldLevel !== $newLevel){ if($oldLevel !== $newLevel){
$this->currentLightArray->set($x & 0xf, $y & 0xf, $z & 0xf, $newLevel); $lightArray->set($x & 0xf, $y & 0xf, $z & 0xf, $newLevel);
if($oldLevel < $newLevel){ //light increased if($oldLevel < $newLevel){ //light increased
$context->spreadVisited[$blockHash] = true; $context->spreadVisited[$blockHash] = true;
$context->spreadQueue->enqueue([$x, $y, $z]); $context->spreadQueue->enqueue([$x, $y, $z]);
@ -172,10 +169,11 @@ abstract class LightUpdate{
} }
protected function computeRemoveLight(int $x, int $y, int $z, int $oldAdjacentLevel, LightPropagationContext $context) : void{ protected function computeRemoveLight(int $x, int $y, int $z, int $oldAdjacentLevel, LightPropagationContext $context) : void{
$current = $this->currentLightArray->get($x & 0xf, $y & 0xf, $z & 0xf); $lightArray = $this->getCurrentLightArray();
$current = $lightArray->get($x & 0xf, $y & 0xf, $z & 0xf);
if($current !== 0 and $current < $oldAdjacentLevel){ if($current !== 0 and $current < $oldAdjacentLevel){
$this->currentLightArray->set($x & 0xf, $y & 0xf, $z & 0xf, 0); $lightArray->set($x & 0xf, $y & 0xf, $z & 0xf, 0);
if(!isset($context->removalVisited[$index = World::blockHash($x, $y, $z)])){ if(!isset($context->removalVisited[$index = World::blockHash($x, $y, $z)])){
$context->removalVisited[$index] = true; $context->removalVisited[$index] = true;
@ -192,11 +190,12 @@ abstract class LightUpdate{
} }
protected function computeSpreadLight(int $x, int $y, int $z, int $newAdjacentLevel, LightPropagationContext $context) : void{ protected function computeSpreadLight(int $x, int $y, int $z, int $newAdjacentLevel, LightPropagationContext $context) : void{
$current = $this->currentLightArray->get($x & 0xf, $y & 0xf, $z & 0xf); $lightArray = $this->getCurrentLightArray();
$current = $lightArray->get($x & 0xf, $y & 0xf, $z & 0xf);
$potentialLight = $newAdjacentLevel - $this->lightFilters[$this->subChunkExplorer->currentSubChunk->getFullBlock($x & 0x0f, $y & 0x0f, $z & 0x0f)]; $potentialLight = $newAdjacentLevel - $this->lightFilters[$this->subChunkExplorer->currentSubChunk->getFullBlock($x & 0x0f, $y & 0x0f, $z & 0x0f)];
if($current < $potentialLight){ if($current < $potentialLight){
$this->currentLightArray->set($x & 0xf, $y & 0xf, $z & 0xf, $potentialLight); $lightArray->set($x & 0xf, $y & 0xf, $z & 0xf, $potentialLight);
if(!isset($context->spreadVisited[$index = World::blockHash($x, $y, $z)]) and $potentialLight > 1){ if(!isset($context->spreadVisited[$index = World::blockHash($x, $y, $z)]) and $potentialLight > 1){
$context->spreadVisited[$index] = true; $context->spreadVisited[$index] = true;

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\world\light; namespace pocketmine\world\light;
use pocketmine\world\format\LightArray;
use pocketmine\world\utils\SubChunkExplorer; use pocketmine\world\utils\SubChunkExplorer;
use pocketmine\world\utils\SubChunkExplorerStatus; use pocketmine\world\utils\SubChunkExplorerStatus;
use pocketmine\world\World; use pocketmine\world\World;
@ -47,8 +48,8 @@ class SkyLightUpdate extends LightUpdate{
$this->directSkyLightBlockers = $directSkyLightBlockers; $this->directSkyLightBlockers = $directSkyLightBlockers;
} }
protected function updateLightArrayRef() : void{ protected function getCurrentLightArray() : LightArray{
$this->currentLightArray = $this->subChunkExplorer->currentSubChunk->getBlockSkyLightArray(); return $this->subChunkExplorer->currentSubChunk->getBlockSkyLightArray();
} }
protected function getEffectiveLight(int $x, int $y, int $z) : int{ protected function getEffectiveLight(int $x, int $y, int $z) : int{