LightUpdate: avoid trying to propagate light into nodes with higher light levels

Track which direction the current node's light came from, and don't
check it again when we check the current node's adjacent blocks.

e.g. if this node was the eastern neighbour of a light source, we don't
need to check this node's western neighbour, as we already know it has
a higher light level than our own.

This improves performance of basic light spread in a void by about 6%,
which isn't a huge amount, but it's something.

I've yet to explore whether light removal could also benefit from this
change.
This commit is contained in:
Dylan K. Taylor 2023-10-09 17:06:02 +01:00
parent 006f78c0a7
commit ee26d6d570
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
2 changed files with 15 additions and 6 deletions

View File

@ -28,8 +28,8 @@ final class LightPropagationContext{
/** @phpstan-var \SplQueue<array{int, int, int}> */ /** @phpstan-var \SplQueue<array{int, int, int}> */
public \SplQueue $spreadQueue; public \SplQueue $spreadQueue;
/** /**
* @var true[] * @var int[]|true[]
* @phpstan-var array<int, true> * @phpstan-var array<int, int|true>
*/ */
public array $spreadVisited = []; public array $spreadVisited = [];

View File

@ -137,6 +137,7 @@ abstract class LightUpdate{
while(!$context->spreadQueue->isEmpty()){ while(!$context->spreadQueue->isEmpty()){
$touched++; $touched++;
[$x, $y, $z] = $context->spreadQueue->dequeue(); [$x, $y, $z] = $context->spreadQueue->dequeue();
$from = $context->spreadVisited[World::blockHash($x, $y, $z)];
unset($context->spreadVisited[World::blockHash($x, $y, $z)]); unset($context->spreadVisited[World::blockHash($x, $y, $z)]);
@ -155,7 +156,11 @@ abstract class LightUpdate{
continue; continue;
} }
foreach(Facing::OFFSET as [$ox, $oy, $oz]){ foreach(Facing::OFFSET as $side => [$ox, $oy, $oz]){
if($from === $side){
//don't check the side that this node received its initial light from
continue;
}
$cx = $x + $ox; $cx = $x + $ox;
$cy = $y + $oy; $cy = $y + $oy;
$cz = $z + $oz; $cz = $z + $oz;
@ -169,7 +174,7 @@ abstract class LightUpdate{
$lightArray = $this->getCurrentLightArray(); $lightArray = $this->getCurrentLightArray();
} }
assert($subChunk !== null); assert($subChunk !== null);
$this->computeSpreadLight($cx, $cy, $cz, $newAdjacentLight, $context, $lightArray, $subChunk); $this->computeSpreadLight($cx, $cy, $cz, $newAdjacentLight, $context, $lightArray, $subChunk, $side);
} }
} }
@ -199,7 +204,7 @@ abstract class LightUpdate{
} }
} }
protected function computeSpreadLight(int $x, int $y, int $z, int $newAdjacentLevel, LightPropagationContext $context, LightArray $lightArray, SubChunk $subChunk) : void{ protected function computeSpreadLight(int $x, int $y, int $z, int $newAdjacentLevel, LightPropagationContext $context, LightArray $lightArray, SubChunk $subChunk, int $side) : void{
$lx = $x & SubChunk::COORD_MASK; $lx = $x & SubChunk::COORD_MASK;
$ly = $y & SubChunk::COORD_MASK; $ly = $y & SubChunk::COORD_MASK;
$lz = $z & SubChunk::COORD_MASK; $lz = $z & SubChunk::COORD_MASK;
@ -210,7 +215,11 @@ abstract class LightUpdate{
$lightArray->set($lx, $ly, $lz, $potentialLight); $lightArray->set($lx, $ly, $lz, $potentialLight);
if(!isset($context->spreadVisited[$index = World::blockHash($x, $y, $z)]) && $potentialLight > 1){ if(!isset($context->spreadVisited[$index = World::blockHash($x, $y, $z)]) && $potentialLight > 1){
$context->spreadVisited[$index] = true; //Track where this node was lit from, to avoid checking the source again when we propagate from here
//TODO: In the future it might be worth tracking more than one adjacent source face in case multiple
//nodes try to light the same node. However, this is a rare case since the vast majority of calls are
//basic propagation with only one source anyway.
$context->spreadVisited[$index] = Facing::opposite($side);
$context->spreadQueue->enqueue([$x, $y, $z]); $context->spreadQueue->enqueue([$x, $y, $z]);
} }
} }