Level: Queue all block updates until the end of tick

this allows deduplicating block updates when lots of adjacent blocks are set on a tick, which has beneficial effects on performance. It also fixes #2659.

Future scope:
- Use this mechanism to deal with explosions properly.
- Don't execute block updates for air blocks.
This commit is contained in:
Dylan K. Taylor 2019-01-13 13:24:02 +00:00
parent d2768188e8
commit 82788774b0

View File

@ -63,7 +63,6 @@ use pocketmine\level\particle\DestroyBlockParticle;
use pocketmine\level\particle\Particle; use pocketmine\level\particle\Particle;
use pocketmine\level\sound\Sound; use pocketmine\level\sound\Sound;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector2; use pocketmine\math\Vector2;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\metadata\BlockMetadataStore; use pocketmine\metadata\BlockMetadataStore;
@ -217,6 +216,8 @@ class Level implements ChunkManager, Metadatable{
/** @var \SplQueue */ /** @var \SplQueue */
private $neighbourBlockUpdateQueue; private $neighbourBlockUpdateQueue;
/** @var bool[] blockhash => dummy */
private $neighbourBlockUpdateQueueIndex = [];
/** @var Player[][] */ /** @var Player[][] */
private $chunkSendQueue = []; private $chunkSendQueue = [];
@ -759,8 +760,12 @@ class Level implements ChunkManager, Metadatable{
$ev = new BlockUpdateEvent($block); $ev = new BlockUpdateEvent($block);
$ev->call(); $ev->call();
if(!$ev->isCancelled()){ if(!$ev->isCancelled()){
foreach($this->getNearbyEntities(AxisAlignedBB::one()->offset($block->x, $block->y, $block->z)) as $entity){
$entity->onNearbyBlockChange();
}
$block->onNearbyBlockChange(); $block->onNearbyBlockChange();
} }
unset($this->neighbourBlockUpdateQueueIndex[$index]);
} }
$this->timings->doTickPending->stopTiming(); $this->timings->doTickPending->stopTiming();
@ -1081,19 +1086,12 @@ class Level implements ChunkManager, Metadatable{
$this->scheduledBlockUpdateQueue->insert(new Vector3((int) $pos->x, (int) $pos->y, (int) $pos->z), $delay + $this->server->getTick()); $this->scheduledBlockUpdateQueue->insert(new Vector3((int) $pos->x, (int) $pos->y, (int) $pos->z), $delay + $this->server->getTick());
} }
/** private function tryAddToNeighbourUpdateQueue(Vector3 $pos) : void{
* Schedules the blocks around the specified position to be updated at the end of this tick. if($this->isInWorld($pos->x, $pos->y, $pos->z)){
* Blocks will be updated with the normal update type. $hash = Level::blockHash($pos->x, $pos->y, $pos->z);
* if(!isset($this->neighbourBlockUpdateQueueIndex[$hash])){
* @param Vector3 $pos $this->neighbourBlockUpdateQueue->enqueue($hash);
*/ $this->neighbourBlockUpdateQueueIndex[$hash] = true;
public function scheduleNeighbourBlockUpdates(Vector3 $pos){
$pos = $pos->floor();
foreach(Facing::ALL as $face){
$side = $pos->getSide($face);
if($this->isInWorld($side->x, $side->y, $side->z)){
$this->neighbourBlockUpdateQueue->enqueue(Level::blockHash($side->x, $side->y, $side->z));
} }
} }
} }
@ -1559,15 +1557,9 @@ class Level implements ChunkManager, Metadatable{
if($update){ if($update){
$this->updateAllLight($block); $this->updateAllLight($block);
$this->tryAddToNeighbourUpdateQueue($block);
$ev = new BlockUpdateEvent($block); foreach($block->sides() as $side){
$ev->call(); $this->tryAddToNeighbourUpdateQueue($side);
if(!$ev->isCancelled()){
foreach($this->getNearbyEntities(AxisAlignedBB::one()->offset($block->x, $block->y, $block->z)->expand(1, 1, 1)) as $entity){
$entity->onNearbyBlockChange();
}
$ev->getBlock()->onNearbyBlockChange();
$this->scheduleNeighbourBlockUpdates($block);
} }
} }