From ee26d6d570a29797d57ea1dddcc5d7a7ff129a76 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 9 Oct 2023 17:06:02 +0100 Subject: [PATCH] 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. --- src/world/light/LightPropagationContext.php | 4 ++-- src/world/light/LightUpdate.php | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/world/light/LightPropagationContext.php b/src/world/light/LightPropagationContext.php index 637535344e..c3d45b3c63 100644 --- a/src/world/light/LightPropagationContext.php +++ b/src/world/light/LightPropagationContext.php @@ -28,8 +28,8 @@ final class LightPropagationContext{ /** @phpstan-var \SplQueue */ public \SplQueue $spreadQueue; /** - * @var true[] - * @phpstan-var array + * @var int[]|true[] + * @phpstan-var array */ public array $spreadVisited = []; diff --git a/src/world/light/LightUpdate.php b/src/world/light/LightUpdate.php index 58ac0a9dcb..b7455c6cc3 100644 --- a/src/world/light/LightUpdate.php +++ b/src/world/light/LightUpdate.php @@ -137,6 +137,7 @@ abstract class LightUpdate{ while(!$context->spreadQueue->isEmpty()){ $touched++; [$x, $y, $z] = $context->spreadQueue->dequeue(); + $from = $context->spreadVisited[World::blockHash($x, $y, $z)]; unset($context->spreadVisited[World::blockHash($x, $y, $z)]); @@ -155,7 +156,11 @@ abstract class LightUpdate{ 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; $cy = $y + $oy; $cz = $z + $oz; @@ -169,7 +174,7 @@ abstract class LightUpdate{ $lightArray = $this->getCurrentLightArray(); } 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; $ly = $y & SubChunk::COORD_MASK; $lz = $z & SubChunk::COORD_MASK; @@ -210,7 +215,11 @@ abstract class LightUpdate{ $lightArray->set($lx, $ly, $lz, $potentialLight); 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]); } }