Significantly improved light population performance using subchunk

direct accessing

These changes produce upwards of 2x better performance (YMMV, also
depends on the circumstances).
This commit is contained in:
Dylan K. Taylor 2017-11-27 20:01:41 +00:00
parent 4703715063
commit d3e5733ea0
3 changed files with 29 additions and 20 deletions

View File

@ -26,10 +26,10 @@ namespace pocketmine\level\light;
class BlockLightUpdate extends LightUpdate{
public function getLight(int $x, int $y, int $z) : int{
return $this->level->getBlockLightAt($x, $y, $z);
return $this->subChunkHandler->currentSubChunk->getBlockLight($x & 0x0f, $y & 0x0f, $z & 0x0f);
}
public function setLight(int $x, int $y, int $z, int $level){
$this->level->setBlockLightAt($x, $y, $z, $level);
$this->subChunkHandler->currentSubChunk->setBlockLight($x & 0x0f, $y & 0x0f, $z & 0x0f, $level);
}
}

View File

@ -26,6 +26,7 @@ namespace pocketmine\level\light;
use pocketmine\block\BlockFactory;
use pocketmine\level\ChunkManager;
use pocketmine\level\Level;
use pocketmine\level\utils\SubChunkIteratorManager;
//TODO: make light updates asynchronous
abstract class LightUpdate{
@ -42,11 +43,15 @@ abstract class LightUpdate{
protected $removalQueue;
/** @var bool[] */
protected $removalVisited = [];
/** @var SubChunkIteratorManager */
protected $subChunkHandler;
public function __construct(ChunkManager $level){
$this->level = $level;
$this->removalQueue = new \SplQueue();
$this->spreadQueue = new \SplQueue();
$this->subChunkHandler = new SubChunkIteratorManager($this->level);
}
public function addSpreadNode(int $x, int $y, int $z){
@ -70,16 +75,18 @@ abstract class LightUpdate{
throw new \InvalidArgumentException("Already have a visit ready for this block");
}
$oldLevel = $this->getLight($x, $y, $z);
if($this->subChunkHandler->moveTo($x, $y, $z)){
$oldLevel = $this->getLight($x, $y, $z);
if($oldLevel !== $newLevel){
$this->setLight($x, $y, $z, $newLevel);
if($oldLevel < $newLevel){ //light increased
$this->spreadVisited[$index] = true;
$this->spreadQueue->enqueue([$x, $y, $z]);
}else{ //light removed
$this->removalVisited[$index] = true;
$this->removalQueue->enqueue([$x, $y, $z, $oldLevel]);
if($oldLevel !== $newLevel){
$this->setLight($x, $y, $z, $newLevel);
if($oldLevel < $newLevel){ //light increased
$this->spreadVisited[$index] = true;
$this->spreadQueue->enqueue([$x, $y, $z]);
}else{ //light removed
$this->removalVisited[$index] = true;
$this->removalQueue->enqueue([$x, $y, $z, $oldLevel]);
}
}
}
}
@ -98,16 +105,19 @@ abstract class LightUpdate{
];
foreach($points as list($cx, $cy, $cz)){
if(!$this->level->isInWorld($cx, $cy, $cz)){
continue;
if($this->subChunkHandler->moveTo($cx, $cy, $cz)){
$this->computeRemoveLight($cx, $cy, $cz, $oldAdjacentLight);
}
$this->computeRemoveLight($cx, $cy, $cz, $oldAdjacentLight);
}
}
while(!$this->spreadQueue->isEmpty()){
list($x, $y, $z) = $this->spreadQueue->dequeue();
if(!$this->subChunkHandler->moveTo($x, $y, $z)){
continue;
}
$newAdjacentLight = $this->getLight($x, $y, $z);
if($newAdjacentLight <= 0){
continue;
@ -123,10 +133,9 @@ abstract class LightUpdate{
];
foreach($points as list($cx, $cy, $cz)){
if(!$this->level->isInWorld($cx, $cy, $cz)){
continue;
if($this->subChunkHandler->moveTo($cx, $cy, $cz)){
$this->computeSpreadLight($cx, $cy, $cz, $newAdjacentLight);
}
$this->computeSpreadLight($cx, $cy, $cz, $newAdjacentLight);
}
}
}
@ -153,7 +162,7 @@ abstract class LightUpdate{
protected function computeSpreadLight(int $x, int $y, int $z, int $newAdjacentLevel){
$current = $this->getLight($x, $y, $z);
$potentialLight = $newAdjacentLevel - BlockFactory::$lightFilter[$this->level->getBlockIdAt($x, $y, $z)];
$potentialLight = $newAdjacentLevel - BlockFactory::$lightFilter[$this->subChunkHandler->currentSubChunk->getBlockId($x & 0x0f, $y & 0x0f, $z & 0x0f)];
if($current < $potentialLight){
$this->setLight($x, $y, $z, $potentialLight);

View File

@ -26,10 +26,10 @@ namespace pocketmine\level\light;
class SkyLightUpdate extends LightUpdate{
public function getLight(int $x, int $y, int $z) : int{
return $this->level->getBlockSkyLightAt($x, $y, $z);
return $this->subChunkHandler->currentSubChunk->getBlockSkyLight($x & 0x0f, $y & 0x0f, $z & 0x0f);
}
public function setLight(int $x, int $y, int $z, int $level){
$this->level->setBlockSkyLightAt($x, $y, $z, $level);
$this->subChunkHandler->currentSubChunk->setBlockSkyLight($x & 0x0f, $y & 0x0f, $z & 0x0f, $level);
}
}