From e1352668d1bfc9d6638afc4c7c43cf17b87430c5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 22 Oct 2019 20:13:46 +0100 Subject: [PATCH] LightPopulationTask: Don't overwrite the whole chunk on completion this is more efficient (less data copied for ITC), fixes #2873, and also fixes terrain changes during task run getting overwritten. This still leaves the problem that the light information provided may be out of date by the time the task completes, but this is nonetheless a step forward. --- src/world/format/Chunk.php | 11 ++++++ src/world/light/LightPopulationTask.php | 49 +++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/world/format/Chunk.php b/src/world/format/Chunk.php index d9b8d1996..0c048832f 100644 --- a/src/world/format/Chunk.php +++ b/src/world/format/Chunk.php @@ -620,6 +620,17 @@ class Chunk{ return $this->heightMap->toArray(); } + /** + * @param int[] $values + * @throws \InvalidArgumentException + */ + public function setHeightMapArray(array $values) : void{ + if(count($values) !== 256){ + throw new \InvalidArgumentException("Expected exactly 256 values"); + } + $this->heightMap = \SplFixedArray::fromArray($values); + } + /** * @return bool */ diff --git a/src/world/light/LightPopulationTask.php b/src/world/light/LightPopulationTask.php index 2583f138d..cf1b60420 100644 --- a/src/world/light/LightPopulationTask.php +++ b/src/world/light/LightPopulationTask.php @@ -27,15 +27,31 @@ use pocketmine\block\BlockFactory; use pocketmine\scheduler\AsyncTask; use pocketmine\world\format\Chunk; use pocketmine\world\format\io\FastChunkSerializer; +use pocketmine\world\format\LightArray; use pocketmine\world\World; +use function igbinary_serialize; +use function igbinary_unserialize; class LightPopulationTask extends AsyncTask{ private const TLS_KEY_WORLD = "world"; public $chunk; + /** @var int */ + private $chunkX; + /** @var int */ + private $chunkZ; + + /** @var string */ + private $resultHeightMap; + /** @var string */ + private $resultSkyLightArrays; + /** @var string */ + private $resultBlockLightArrays; + public function __construct(World $world, Chunk $chunk){ $this->storeLocal(self::TLS_KEY_WORLD, $world); + [$this->chunkX, $this->chunkZ] = [$chunk->getX(), $chunk->getZ()]; $this->chunk = FastChunkSerializer::serialize($chunk); } @@ -50,16 +66,41 @@ class LightPopulationTask extends AsyncTask{ $chunk->populateSkyLight(); $chunk->setLightPopulated(); - $this->chunk = FastChunkSerializer::serialize($chunk); + $this->resultHeightMap = igbinary_serialize($chunk->getHeightMapArray()); + $skyLightArrays = []; + $blockLightArrays = []; + foreach($chunk->getSubChunks() as $y => $subChunk){ + $skyLightArrays[$y] = $subChunk->getBlockSkyLightArray(); + $blockLightArrays[$y] = $subChunk->getBlockLightArray(); + } + $this->resultSkyLightArrays = igbinary_serialize($skyLightArrays); + $this->resultBlockLightArrays = igbinary_serialize($blockLightArrays); } public function onCompletion() : void{ /** @var World $world */ $world = $this->fetchLocal(self::TLS_KEY_WORLD); - if(!$world->isClosed()){ + if(!$world->isClosed() and $world->isChunkLoaded($this->chunkX, $this->chunkZ)){ /** @var Chunk $chunk */ - $chunk = FastChunkSerializer::deserialize($this->chunk); - $world->generateChunkCallback($chunk->getX(), $chunk->getZ(), $chunk); + $chunk = $world->getChunk($this->chunkX, $this->chunkZ); + //TODO: calculated light information might not be valid if the terrain changed during light calculation + + /** @var int[] $heightMapArray */ + $heightMapArray = igbinary_unserialize($this->resultHeightMap); + $chunk->setHeightMapArray($heightMapArray); + + /** @var LightArray[] $skyLightArrays */ + $skyLightArrays = igbinary_unserialize($this->resultSkyLightArrays); + /** @var LightArray[] $blockLightArrays */ + $blockLightArrays = igbinary_unserialize($this->resultBlockLightArrays); + + foreach($skyLightArrays as $y => $array){ + $chunk->getSubChunk($y, true)->setBlockSkyLightArray($array); + } + foreach($blockLightArrays as $y => $array){ + $chunk->getSubChunk($y, true)->setBlockLightArray($array); + } + $chunk->setLightPopulated(); } } }