mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-05-12 16:59:44 +00:00
encapsulate light recalculation logic inside LightUpdate classes
now we can do a standard light recalculation from anywhere.
This commit is contained in:
parent
3d118a415c
commit
ceb6529ee3
@ -1397,39 +1397,10 @@ class World implements ChunkManager{
|
||||
public function updateBlockSkyLight(int $x, int $y, int $z){
|
||||
$this->timings->doBlockSkyLightUpdates->startTiming();
|
||||
|
||||
$oldHeightMap = $this->getHeightMap($x, $z);
|
||||
$source = $this->getBlockAt($x, $y, $z);
|
||||
|
||||
$yPlusOne = $y + 1;
|
||||
|
||||
if($yPlusOne === $oldHeightMap){ //Block changed directly beneath the heightmap. Check if a block was removed or changed to a different light-filter.
|
||||
$newHeightMap = $this->getChunk($x >> 4, $z >> 4)->recalculateHeightMapColumn($x & 0x0f, $z & 0x0f);
|
||||
}elseif($yPlusOne > $oldHeightMap){ //Block changed above the heightmap.
|
||||
if($source->getLightFilter() > 0 or $source->diffusesSkyLight()){
|
||||
$this->setHeightMap($x, $z, $yPlusOne);
|
||||
$newHeightMap = $yPlusOne;
|
||||
}else{ //Block changed which has no effect on direct sky light, for example placing or removing glass.
|
||||
$this->timings->doBlockSkyLightUpdates->stopTiming();
|
||||
return;
|
||||
}
|
||||
}else{ //Block changed below heightmap
|
||||
$newHeightMap = $oldHeightMap;
|
||||
}
|
||||
|
||||
if($this->skyLightUpdate === null){
|
||||
$this->skyLightUpdate = new SkyLightUpdate($this);
|
||||
}
|
||||
if($newHeightMap > $oldHeightMap){ //Heightmap increase, block placed, remove sky light
|
||||
for($i = $y; $i >= $oldHeightMap; --$i){
|
||||
$this->skyLightUpdate->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
|
||||
for($i = $y; $i >= $newHeightMap; --$i){
|
||||
$this->skyLightUpdate->setAndUpdateLight($x, $i, $z, 15);
|
||||
}
|
||||
}else{ //No heightmap change, block changed "underground"
|
||||
$this->skyLightUpdate->setAndUpdateLight($x, $y, $z, max(0, $this->getHighestAdjacentBlockSkyLight($x, $y, $z) - BlockFactory::$lightFilter[($source->getId() << 4) | $source->getMeta()]));
|
||||
}
|
||||
$this->skyLightUpdate->recalculateNode($x, $y, $z);
|
||||
|
||||
$this->timings->doBlockSkyLightUpdates->stopTiming();
|
||||
}
|
||||
@ -1457,13 +1428,10 @@ class World implements ChunkManager{
|
||||
public function updateBlockLight(int $x, int $y, int $z){
|
||||
$this->timings->doBlockLightUpdates->startTiming();
|
||||
|
||||
$block = $this->getBlockAt($x, $y, $z);
|
||||
$newLevel = max($block->getLightLevel(), $this->getHighestAdjacentBlockLight($x, $y, $z) - BlockFactory::$lightFilter[($block->getId() << 4) | $block->getMeta()]);
|
||||
|
||||
if($this->blockLightUpdate === null){
|
||||
$this->blockLightUpdate = new BlockLightUpdate($this);
|
||||
}
|
||||
$this->blockLightUpdate->setAndUpdateLight($x, $y, $z, $newLevel);
|
||||
$this->blockLightUpdate->recalculateNode($x, $y, $z);
|
||||
|
||||
$this->timings->doBlockLightUpdates->stopTiming();
|
||||
}
|
||||
|
@ -23,6 +23,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\world\light;
|
||||
|
||||
use pocketmine\block\BlockFactory;
|
||||
use function max;
|
||||
|
||||
class BlockLightUpdate extends LightUpdate{
|
||||
|
||||
public function getLight(int $x, int $y, int $z) : int{
|
||||
@ -32,4 +35,9 @@ class BlockLightUpdate extends LightUpdate{
|
||||
public function setLight(int $x, int $y, int $z, int $level) : void{
|
||||
$this->subChunkHandler->currentSubChunk->setBlockLight($x & 0x0f, $y & 0x0f, $z & 0x0f, $level);
|
||||
}
|
||||
|
||||
public function recalculateNode(int $x, int $y, int $z) : void{
|
||||
$block = $this->world->getBlockAt($x, $y, $z);
|
||||
$this->setAndUpdateLight($x, $y, $z, max($block->getLightLevel(), $this->getHighestAdjacentLight($x, $y, $z) - BlockFactory::$lightFilter[$block->getFullId()]));
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ use pocketmine\block\BlockFactory;
|
||||
use pocketmine\world\ChunkManager;
|
||||
use pocketmine\world\utils\SubChunkIteratorManager;
|
||||
use pocketmine\world\World;
|
||||
use function max;
|
||||
|
||||
//TODO: make light updates asynchronous
|
||||
abstract class LightUpdate{
|
||||
@ -61,6 +62,25 @@ abstract class LightUpdate{
|
||||
|
||||
abstract protected function setLight(int $x, int $y, int $z, int $level) : void;
|
||||
|
||||
abstract public function recalculateNode(int $x, int $y, int $z) : void;
|
||||
|
||||
protected function getHighestAdjacentLight(int $x, int $y, int $z) : int{
|
||||
$adjacent = 0;
|
||||
foreach([
|
||||
[$x + 1, $y, $z],
|
||||
[$x - 1, $y, $z],
|
||||
[$x, $y + 1, $z],
|
||||
[$x, $y - 1, $z],
|
||||
[$x, $y, $z + 1],
|
||||
[$x, $y, $z - 1]
|
||||
] as [$x1, $y1, $z1]){
|
||||
if($this->subChunkHandler->moveTo($x1, $y1, $z1, false) and ($adjacent = max($adjacent, $this->getLight($x1, $y1, $z1))) === 15){
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $adjacent;
|
||||
}
|
||||
|
||||
public function setAndUpdateLight(int $x, int $y, int $z, int $newLevel) : void{
|
||||
$this->updateNodes[World::blockHash($x, $y, $z)] = [$x, $y, $z, $newLevel];
|
||||
}
|
||||
|
@ -23,6 +23,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\world\light;
|
||||
|
||||
use pocketmine\block\BlockFactory;
|
||||
use function max;
|
||||
|
||||
class SkyLightUpdate extends LightUpdate{
|
||||
|
||||
public function getLight(int $x, int $y, int $z) : int{
|
||||
@ -32,4 +35,40 @@ class SkyLightUpdate extends LightUpdate{
|
||||
public function setLight(int $x, int $y, int $z, int $level) : void{
|
||||
$this->subChunkHandler->currentSubChunk->setBlockSkyLight($x & 0x0f, $y & 0x0f, $z & 0x0f, $level);
|
||||
}
|
||||
|
||||
public function recalculateNode(int $x, int $y, int $z) : void{
|
||||
$chunk = $this->world->getChunk($x >> 4, $z >> 4);
|
||||
if($chunk === null){
|
||||
return;
|
||||
}
|
||||
$oldHeightMap = $chunk->getHeightMap($x & 0xf, $z & 0xf);
|
||||
$source = $this->world->getBlockAt($x, $y, $z);
|
||||
|
||||
$yPlusOne = $y + 1;
|
||||
|
||||
if($yPlusOne === $oldHeightMap){ //Block changed directly beneath the heightmap. Check if a block was removed or changed to a different light-filter.
|
||||
$newHeightMap = $chunk->recalculateHeightMapColumn($x & 0x0f, $z & 0x0f);
|
||||
}elseif($yPlusOne > $oldHeightMap){ //Block changed above the heightmap.
|
||||
if($source->getLightFilter() > 0 or $source->diffusesSkyLight()){
|
||||
$chunk->setHeightMap($x & 0xf, $z & 0xf, $yPlusOne);
|
||||
$newHeightMap = $yPlusOne;
|
||||
}else{ //Block changed which has no effect on direct sky light, for example placing or removing glass.
|
||||
return;
|
||||
}
|
||||
}else{ //Block changed below heightmap
|
||||
$newHeightMap = $oldHeightMap;
|
||||
}
|
||||
|
||||
if($newHeightMap > $oldHeightMap){ //Heightmap increase, block placed, remove sky light
|
||||
for($i = $y; $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
|
||||
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) - BlockFactory::$lightFilter[$source->getFullId()]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user