SkyLightUpdate: deal with effective light during initial node discovery

this allows the propagation stage to ignore effective light, which allows for further optimisations.
This commit is contained in:
Dylan K. Taylor 2023-05-01 22:29:31 +01:00
parent d80f65ae7c
commit d0b9234841
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
2 changed files with 47 additions and 39 deletions

View File

@ -106,9 +106,6 @@ abstract class LightUpdate{
$context->removalQueue->enqueue([$x, $y, $z, $oldLevel]);
}
}
}elseif($this->getEffectiveLight($x, $y, $z) > 0){ //outside the chunk (e.g. virtual sky light from y=256)
$context->spreadVisited[$blockHash] = true;
$context->spreadQueue->enqueue([$x, $y, $z]);
}
}
return $context;
@ -129,9 +126,6 @@ abstract class LightUpdate{
if($this->subChunkExplorer->moveTo($cx, $cy, $cz) !== SubChunkExplorerStatus::INVALID){
$this->computeRemoveLight($cx, $cy, $cz, $oldAdjacentLight, $context);
}elseif($this->getEffectiveLight($cx, $cy, $cz) > 0 && !isset($context->spreadVisited[$index = World::blockHash($cx, $cy, $cz)])){
$context->spreadVisited[$index] = true;
$context->spreadQueue->enqueue([$cx, $cy, $cz]);
}
}
}
@ -142,7 +136,10 @@ abstract class LightUpdate{
unset($context->spreadVisited[World::blockHash($x, $y, $z)]);
$newAdjacentLight = $this->getEffectiveLight($x, $y, $z);
if($this->subChunkExplorer->moveTo($x, $y, $z) === SubChunkExplorerStatus::INVALID){
continue;
}
$newAdjacentLight = $this->getCurrentLightArray()->get($x & SubChunk::COORD_MASK, $y & SubChunk::COORD_MASK, $z & SubChunk::COORD_MASK);
if($newAdjacentLight <= 0){
continue;
}

View File

@ -84,16 +84,17 @@ class SkyLightUpdate extends LightUpdate{
$newHeightMap = $oldHeightMap;
}
if($newHeightMap > $oldHeightMap){ //Heightmap increase, block placed, remove sky light
for($i = $y; $i >= $oldHeightMap; --$i){
if($newHeightMap >= $oldHeightMap){
for($i = $y - 1; $i >= $oldHeightMap; --$i){
$this->setAndUpdateLight($x, $i, $z, 0); //Remove all light beneath, adjacent recalculation will handle the rest.
}
}elseif($newHeightMap < $oldHeightMap){ //Heightmap decrease, block changed or removed, add sky light
//recalculate light for the placed block from its surroundings - this avoids having to check effective light during propagation
$this->setAndUpdateLight($x, $y, $z, max(0, $this->getHighestAdjacentLight($x, $y, $z) - ($this->lightFilters[$source] ?? self::BASE_LIGHT_FILTER)));
}else{ //Heightmap decrease, block changed or removed, add sky light
for($i = $y; $i >= $newHeightMap; --$i){
$this->setAndUpdateLight($x, $i, $z, 15);
}
}else{ //No heightmap change, block changed "underground"
$this->setAndUpdateLight($x, $y, $z, max(0, $this->getHighestAdjacentLight($x, $y, $z) - ($this->lightFilters[$source] ?? self::BASE_LIGHT_FILTER)));
}
}
@ -124,35 +125,45 @@ class SkyLightUpdate extends LightUpdate{
for($x = 0; $x < Chunk::EDGE_LENGTH; ++$x){
for($z = 0; $z < Chunk::EDGE_LENGTH; ++$z){
$currentHeight = $chunk->getHeightMap($x, $z);
$maxAdjacentHeight = World::Y_MIN;
if($x !== 0){
$maxAdjacentHeight = max($maxAdjacentHeight, $chunk->getHeightMap($x - 1, $z));
}
if($x !== 15){
$maxAdjacentHeight = max($maxAdjacentHeight, $chunk->getHeightMap($x + 1, $z));
}
if($z !== 0){
$maxAdjacentHeight = max($maxAdjacentHeight, $chunk->getHeightMap($x, $z - 1));
}
if($z !== 15){
$maxAdjacentHeight = max($maxAdjacentHeight, $chunk->getHeightMap($x, $z + 1));
}
/*
* We skip the top two blocks between current height and max adjacent (if there's a difference) because:
* - the block next to the highest adjacent will do nothing during propagation (it's surrounded by 15s)
* - the block below that block will do the same as the node in the highest adjacent
* NOTE: If block opacity becomes direction-aware in the future, the second point will become invalid.
*/
$nodeColumnEnd = max($currentHeight, $maxAdjacentHeight - 2);
for($y = $currentHeight; $y <= $nodeColumnEnd; $y++){
$this->setAndUpdateLight($x + $baseX, $y, $z + $baseZ, 15);
$lightSources++;
}
for($y = $nodeColumnEnd + 1, $yMax = $lowestClearSubChunk * SubChunk::EDGE_LENGTH; $y < $yMax; $y++){
if($currentHeight === World::Y_MAX){
//this column has a light-filtering block in the top cell - make sure it's lit from above the world
//light from above the world bounds will not be checked during propagation
$y = $currentHeight - 1;
if($this->subChunkExplorer->moveTo($x + $baseX, $y, $z + $baseZ) !== SubChunkExplorerStatus::INVALID){
$this->getCurrentLightArray()->set($x, $y & SubChunk::COORD_MASK, $z, 15);
$block = $this->subChunkExplorer->currentSubChunk->getBlockStateId($x, $y & SubChunk::COORD_MASK, $z);
$this->setAndUpdateLight($x + $baseX, $y, $z + $baseZ, max(0, 15 - ($this->lightFilters[$block] ?? self::BASE_LIGHT_FILTER)));
}
}else{
$maxAdjacentHeight = World::Y_MIN;
if($x !== 0){
$maxAdjacentHeight = max($maxAdjacentHeight, $chunk->getHeightMap($x - 1, $z));
}
if($x !== 15){
$maxAdjacentHeight = max($maxAdjacentHeight, $chunk->getHeightMap($x + 1, $z));
}
if($z !== 0){
$maxAdjacentHeight = max($maxAdjacentHeight, $chunk->getHeightMap($x, $z - 1));
}
if($z !== 15){
$maxAdjacentHeight = max($maxAdjacentHeight, $chunk->getHeightMap($x, $z + 1));
}
/*
* We skip the top two blocks between current height and max adjacent (if there's a difference) because:
* - the block next to the highest adjacent will do nothing during propagation (it's surrounded by 15s)
* - the block below that block will do the same as the node in the highest adjacent
* NOTE: If block opacity becomes direction-aware in the future, the second point will become invalid.
*/
$nodeColumnEnd = max($currentHeight, $maxAdjacentHeight - 2);
for($y = $currentHeight; $y <= $nodeColumnEnd; $y++){
$this->setAndUpdateLight($x + $baseX, $y, $z + $baseZ, 15);
$lightSources++;
}
for($y = $nodeColumnEnd + 1, $yMax = $lowestClearSubChunk * SubChunk::EDGE_LENGTH; $y < $yMax; $y++){
if($this->subChunkExplorer->moveTo($x + $baseX, $y, $z + $baseZ) !== SubChunkExplorerStatus::INVALID){
$this->getCurrentLightArray()->set($x, $y & SubChunk::COORD_MASK, $z, 15);
}
}
}
}