Fixed getBlock() performance degradation caused by 781de3efabcd526281fd1adc8ce881d408471563, added Level->getBlockAt() to avoid creating vectors everywhere

This commit is contained in:
Dylan K. Taylor 2017-10-20 13:22:49 +01:00
parent 98cfd0b398
commit 18e4e5364f
10 changed files with 88 additions and 69 deletions

View File

@ -2579,7 +2579,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
} }
public function handleBlockPickRequest(BlockPickRequestPacket $packet) : bool{ public function handleBlockPickRequest(BlockPickRequestPacket $packet) : bool{
$block = $this->level->getBlock($this->temporalVector->setComponents($packet->blockX, $packet->blockY, $packet->blockZ)); $block = $this->level->getBlockAt($packet->blockX, $packet->blockY, $packet->blockZ);
//TODO: this doesn't handle crops correctly (need more API work) //TODO: this doesn't handle crops correctly (need more API work)
$item = Item::get($block->getItemId(), $block->getVariant()); $item = Item::get($block->getItemId(), $block->getVariant());

View File

@ -92,7 +92,7 @@ class Cactus extends Transparent{
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::CACTUS){ if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::CACTUS){
if($this->meta === 0x0f){ if($this->meta === 0x0f){
for($y = 1; $y < 3; ++$y){ for($y = 1; $y < 3; ++$y){
$b = $this->getLevel()->getBlock(new Vector3($this->x, $this->y + $y, $this->z)); $b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
if($b->getId() === self::AIR){ if($b->getId() === self::AIR){
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, BlockFactory::get(Block::CACTUS))); Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, BlockFactory::get(Block::CACTUS)));
if(!$ev->isCancelled()){ if(!$ev->isCancelled()){

View File

@ -76,23 +76,22 @@ class Grass extends Solid{
return Level::BLOCK_UPDATE_RANDOM; return Level::BLOCK_UPDATE_RANDOM;
}elseif($lightAbove >= 9){ }elseif($lightAbove >= 9){
//try grass spread //try grass spread
$vector = $this->asVector3();
for($i = 0; $i < 4; ++$i){ for($i = 0; $i < 4; ++$i){
$vector->x = mt_rand($this->x - 1, $this->x + 1); $x = mt_rand($this->x - 1, $this->x + 1);
$vector->y = mt_rand($this->y - 3, $this->y + 1); $y = mt_rand($this->y - 3, $this->y + 1);
$vector->z = mt_rand($this->z - 1, $this->z + 1); $z = mt_rand($this->z - 1, $this->z + 1);
if( if(
$this->level->getBlockIdAt($vector->x, $vector->y, $vector->z) !== Block::DIRT or $this->level->getBlockIdAt($x, $y, $z) !== Block::DIRT or
$this->level->getBlockDataAt($vector->x, $vector->y, $vector->z) === 1 or $this->level->getBlockDataAt($x, $y, $z) === 1 or
$this->level->getFullLightAt($vector->x, $vector->y + 1, $vector->z) < 4 or $this->level->getFullLightAt($x, $y + 1, $z) < 4 or
BlockFactory::$lightFilter[$this->level->getBlockIdAt($vector->x, $vector->y + 1, $vector->z)] >= 3 BlockFactory::$lightFilter[$this->level->getBlockIdAt($x, $y + 1, $z)] >= 3
){ ){
continue; continue;
} }
$this->level->getServer()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($this->level->getBlock($vector), $this, BlockFactory::get(Block::GRASS))); $this->level->getServer()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($b = $this->level->getBlockAt($x, $y, $z), $this, BlockFactory::get(Block::GRASS)));
if(!$ev->isCancelled()){ if(!$ev->isCancelled()){
$this->level->setBlock($vector, $ev->getNewState(), false, false); $this->level->setBlock($b, $ev->getNewState(), false, false);
} }
} }

View File

@ -117,7 +117,7 @@ abstract class Liquid extends Transparent{
}elseif($j === 3){ }elseif($j === 3){
++$z; ++$z;
} }
$sideBlock = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z)); $sideBlock = $this->getLevel()->getBlockAt($x, $y, $z);
$blockDecay = $this->getEffectiveFlowDecay($sideBlock); $blockDecay = $this->getEffectiveFlowDecay($sideBlock);
if($blockDecay < 0){ if($blockDecay < 0){
@ -125,7 +125,7 @@ abstract class Liquid extends Transparent{
continue; continue;
} }
$blockDecay = $this->getEffectiveFlowDecay($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z))); $blockDecay = $this->getEffectiveFlowDecay($this->getLevel()->getBlockAt($x, $y - 1, $z));
if($blockDecay >= 0){ if($blockDecay >= 0){
$realDecay = $blockDecay - ($decay - 8); $realDecay = $blockDecay - ($decay - 8);
@ -146,21 +146,21 @@ abstract class Liquid extends Transparent{
if($this->getDamage() >= 8){ if($this->getDamage() >= 8){
$falling = false; $falling = false;
if(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1))->canBeFlowedInto()){ if(!$this->getLevel()->getBlockAt($this->x, $this->y, $this->z - 1)->canBeFlowedInto()){
$falling = true; $falling = true;
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1))->canBeFlowedInto()){ }elseif(!$this->getLevel()->getBlockAt($this->x, $this->y, $this->z + 1)->canBeFlowedInto()){
$falling = true; $falling = true;
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z))->canBeFlowedInto()){ }elseif(!$this->getLevel()->getBlockAt($this->x - 1, $this->y, $this->z)->canBeFlowedInto()){
$falling = true; $falling = true;
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z))->canBeFlowedInto()){ }elseif(!$this->getLevel()->getBlockAt($this->x + 1, $this->y, $this->z)->canBeFlowedInto()){
$falling = true; $falling = true;
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z - 1))->canBeFlowedInto()){ }elseif(!$this->getLevel()->getBlockAt($this->x, $this->y + 1, $this->z - 1)->canBeFlowedInto()){
$falling = true; $falling = true;
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z + 1))->canBeFlowedInto()){ }elseif(!$this->getLevel()->getBlockAt($this->x, $this->y + 1, $this->z + 1)->canBeFlowedInto()){
$falling = true; $falling = true;
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y + 1, $this->z))->canBeFlowedInto()){ }elseif(!$this->getLevel()->getBlockAt($this->x - 1, $this->y + 1, $this->z)->canBeFlowedInto()){
$falling = true; $falling = true;
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y + 1, $this->z))->canBeFlowedInto()){ }elseif(!$this->getLevel()->getBlockAt($this->x + 1, $this->y + 1, $this->z)->canBeFlowedInto()){
$falling = true; $falling = true;
} }
@ -206,10 +206,10 @@ abstract class Liquid extends Transparent{
if($decay > 0){ if($decay > 0){
$smallestFlowDecay = -100; $smallestFlowDecay = -100;
$this->adjacentSources = 0; $this->adjacentSources = 0;
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1)), $smallestFlowDecay); $smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x, $this->y, $this->z - 1), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1)), $smallestFlowDecay); $smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x, $this->y, $this->z + 1), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z)), $smallestFlowDecay); $smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x - 1, $this->y, $this->z), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z)), $smallestFlowDecay); $smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x + 1, $this->y, $this->z), $smallestFlowDecay);
$k = $smallestFlowDecay + $multiplier; $k = $smallestFlowDecay + $multiplier;
@ -217,7 +217,7 @@ abstract class Liquid extends Transparent{
$k = -1; $k = -1;
} }
if(($topFlowDecay = $this->getFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z)))) >= 0){ if(($topFlowDecay = $this->getFlowDecay($this->level->getBlockAt($this->x, $this->y + 1, $this->z))) >= 0){
if($topFlowDecay >= 8){ if($topFlowDecay >= 8){
$k = $topFlowDecay; $k = $topFlowDecay;
}else{ }else{
@ -226,7 +226,7 @@ abstract class Liquid extends Transparent{
} }
if($this->adjacentSources >= 2 and $this instanceof Water){ if($this->adjacentSources >= 2 and $this instanceof Water){
$bottomBlock = $this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y - 1, $this->z)); $bottomBlock = $this->level->getBlockAt($this->x, $this->y - 1, $this->z);
if($bottomBlock->isSolid()){ if($bottomBlock->isSolid()){
$k = 0; $k = 0;
}elseif($bottomBlock instanceof Water and $bottomBlock->getDamage() === 0){ }elseif($bottomBlock instanceof Water and $bottomBlock->getDamage() === 0){
@ -256,7 +256,7 @@ abstract class Liquid extends Transparent{
} }
if($decay >= 0){ if($decay >= 0){
$bottomBlock = $this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y - 1, $this->z)); $bottomBlock = $this->level->getBlockAt($this->x, $this->y - 1, $this->z);
if($this instanceof Lava and $bottomBlock instanceof Water){ if($this instanceof Lava and $bottomBlock instanceof Water){
$this->getLevel()->setBlock($bottomBlock, BlockFactory::get(Block::STONE), true, true); $this->getLevel()->setBlock($bottomBlock, BlockFactory::get(Block::STONE), true, true);
@ -281,19 +281,19 @@ abstract class Liquid extends Transparent{
} }
if($flags[0]){ if($flags[0]){
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z)), $l); $this->flowIntoBlock($this->level->getBlockAt($this->x - 1, $this->y, $this->z), $l);
} }
if($flags[1]){ if($flags[1]){
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z)), $l); $this->flowIntoBlock($this->level->getBlockAt($this->x + 1, $this->y, $this->z), $l);
} }
if($flags[2]){ if($flags[2]){
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1)), $l); $this->flowIntoBlock($this->level->getBlockAt($this->x, $this->y, $this->z - 1), $l);
} }
if($flags[3]){ if($flags[3]){
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1)), $l); $this->flowIntoBlock($this->level->getBlockAt($this->x, $this->y, $this->z + 1), $l);
} }
} }
@ -336,13 +336,13 @@ abstract class Liquid extends Transparent{
}elseif($j === 3){ }elseif($j === 3){
++$z; ++$z;
} }
$blockSide = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z)); $blockSide = $this->getLevel()->getBlockAt($x, $y, $z);
if(!$blockSide->canBeFlowedInto() and !($blockSide instanceof Liquid)){ if(!$blockSide->canBeFlowedInto() and !($blockSide instanceof Liquid)){
continue; continue;
}elseif($blockSide instanceof Liquid and $blockSide->getDamage() === 0){ }elseif($blockSide instanceof Liquid and $blockSide->getDamage() === 0){
continue; continue;
}elseif($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z))->canBeFlowedInto()){ }elseif($this->getLevel()->getBlockAt($x, $y - 1, $z)->canBeFlowedInto()){
return $accumulatedCost; return $accumulatedCost;
} }
@ -386,13 +386,13 @@ abstract class Liquid extends Transparent{
}elseif($j === 3){ }elseif($j === 3){
++$z; ++$z;
} }
$block = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z)); $block = $this->getLevel()->getBlockAt($x, $y, $z);
if(!$block->canBeFlowedInto() and !($block instanceof Liquid)){ if(!$block->canBeFlowedInto() and !($block instanceof Liquid)){
continue; continue;
}elseif($block instanceof Liquid and $block->getDamage() === 0){ }elseif($block instanceof Liquid and $block->getDamage() === 0){
continue; continue;
}elseif($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z))->canBeFlowedInto()){ }elseif($this->getLevel()->getBlockAt($x, $y - 1, $z)->canBeFlowedInto()){
$this->flowCost[$j] = 0; $this->flowCost[$j] = 0;
}else{ }else{
$this->flowCost[$j] = $this->calculateFlowCost($block, 1, $j); $this->flowCost[$j] = $this->calculateFlowCost($block, 1, $j);

View File

@ -67,7 +67,7 @@ class Mycelium extends Solid{
$x = mt_rand($this->x - 1, $this->x + 1); $x = mt_rand($this->x - 1, $this->x + 1);
$y = mt_rand($this->y - 2, $this->y + 2); $y = mt_rand($this->y - 2, $this->y + 2);
$z = mt_rand($this->z - 1, $this->z + 1); $z = mt_rand($this->z - 1, $this->z + 1);
$block = $this->getLevel()->getBlock(new Vector3($x, $y, $z)); $block = $this->getLevel()->getBlockAt($x, $y, $z);
if($block->getId() === Block::DIRT){ if($block->getId() === Block::DIRT){
if($block->getSide(Vector3::SIDE_UP) instanceof Transparent){ if($block->getSide(Vector3::SIDE_UP) instanceof Transparent){
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($block, $this, BlockFactory::get(Block::MYCELIUM))); Server::getInstance()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($block, $this, BlockFactory::get(Block::MYCELIUM)));

View File

@ -52,7 +52,7 @@ class Sugarcane extends Flowable{
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){ if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){
for($y = 1; $y < 3; ++$y){ for($y = 1; $y < 3; ++$y){
$b = $this->getLevel()->getBlock(new Vector3($this->x, $this->y + $y, $this->z)); $b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
if($b->getId() === self::AIR){ if($b->getId() === self::AIR){
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, BlockFactory::get(Block::SUGARCANE_BLOCK))); Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, BlockFactory::get(Block::SUGARCANE_BLOCK)));
if(!$ev->isCancelled()){ if(!$ev->isCancelled()){
@ -85,7 +85,7 @@ class Sugarcane extends Flowable{
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){ if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){
if($this->meta === 0x0F){ if($this->meta === 0x0F){
for($y = 1; $y < 3; ++$y){ for($y = 1; $y < 3; ++$y){
$b = $this->getLevel()->getBlock(new Vector3($this->x, $this->y + $y, $this->z)); $b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
if($b->getId() === self::AIR){ if($b->getId() === self::AIR){
$this->getLevel()->setBlock($b, BlockFactory::get(Block::SUGARCANE_BLOCK), true); $this->getLevel()->setBlock($b, BlockFactory::get(Block::SUGARCANE_BLOCK), true);
break; break;

View File

@ -1105,7 +1105,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
} }
if($this->onGround){ if($this->onGround){
$friction *= $this->level->getBlock($this->floor()->subtract(0, 1, 0))->getFrictionFactor(); $friction *= $this->level->getBlockAt(Math::floorFloat($this->x), Math::floorFloat($this->y) - 1, Math::floorFloat($this->z))->getFrictionFactor();
} }
$this->motionX *= $friction; $this->motionX *= $friction;
@ -1385,7 +1385,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
} }
public function isInsideOfWater() : bool{ public function isInsideOfWater() : bool{
$block = $this->level->getBlock($this->temporalVector->setComponents(Math::floorFloat($this->x), Math::floorFloat($y = ($this->y + $this->getEyeHeight())), Math::floorFloat($this->z))); $block = $this->level->getBlockAt(Math::floorFloat($this->x), Math::floorFloat($y = ($this->y + $this->getEyeHeight())), Math::floorFloat($this->z));
if($block instanceof Water){ if($block instanceof Water){
$f = ($block->y + 1) - ($block->getFluidHeightPercent() - 0.1111111); $f = ($block->y + 1) - ($block->getFluidHeightPercent() - 0.1111111);
@ -1396,7 +1396,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
} }
public function isInsideOfSolid() : bool{ public function isInsideOfSolid() : bool{
$block = $this->level->getBlock($this->temporalVector->setComponents(Math::floorFloat($this->x), Math::floorFloat($y = ($this->y + $this->getEyeHeight())), Math::floorFloat($this->z))); $block = $this->level->getBlockAt(Math::floorFloat($this->x), Math::floorFloat($y = ($this->y + $this->getEyeHeight())), Math::floorFloat($this->z));
return $block->isSolid() and !$block->isTransparent() and $block->collidesWithBB($this->getBoundingBox()); return $block->isSolid() and !$block->isTransparent() and $block->collidesWithBB($this->getBoundingBox());
} }
@ -1627,7 +1627,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
for($z = $minZ; $z <= $maxZ; ++$z){ for($z = $minZ; $z <= $maxZ; ++$z){
for($x = $minX; $x <= $maxX; ++$x){ for($x = $minX; $x <= $maxX; ++$x){
for($y = $minY; $y <= $maxY; ++$y){ for($y = $minY; $y <= $maxY; ++$y){
$block = $this->level->getBlock($this->temporalVector->setComponents($x, $y, $z)); $block = $this->level->getBlockAt($x, $y, $z);
if($block->hasEntityCollision()){ if($block->hasEntityCollision()){
$this->blocksAround[] = $block; $this->blocksAround[] = $block;
} }

View File

@ -232,7 +232,7 @@ class Explosion{
continue; continue;
} }
if(!isset($this->affectedBlocks[$index = Level::blockHash($sideBlock->x, $sideBlock->y, $sideBlock->z)]) and !isset($updateBlocks[$index])){ if(!isset($this->affectedBlocks[$index = Level::blockHash($sideBlock->x, $sideBlock->y, $sideBlock->z)]) and !isset($updateBlocks[$index])){
$this->level->getServer()->getPluginManager()->callEvent($ev = new BlockUpdateEvent($this->level->getBlock($sideBlock))); $this->level->getServer()->getPluginManager()->callEvent($ev = new BlockUpdateEvent($this->level->getBlockAt($sideBlock->x, $sideBlock->y, $sideBlock->z)));
if(!$ev->isCancelled()){ if(!$ev->isCancelled()){
$ev->getBlock()->onUpdate(Level::BLOCK_UPDATE_NORMAL); $ev->getBlock()->onUpdate(Level::BLOCK_UPDATE_NORMAL);
} }

View File

@ -706,7 +706,7 @@ class Level implements ChunkManager, Metadatable{
$index = $this->neighbourBlockUpdateQueue->dequeue(); $index = $this->neighbourBlockUpdateQueue->dequeue();
Level::getBlockXYZ($index, $x, $y, $z); Level::getBlockXYZ($index, $x, $y, $z);
$block = $this->getBlock($this->temporalVector->setComponents($x, $y, $z)); $block = $this->getBlockAt($x, $y, $z);
$block->clearBoundingBoxes(); //for blocks like fences, force recalculation of connected AABBs $block->clearBoundingBoxes(); //for blocks like fences, force recalculation of connected AABBs
$this->server->getPluginManager()->callEvent($ev = new BlockUpdateEvent($block)); $this->server->getPluginManager()->callEvent($ev = new BlockUpdateEvent($block));
@ -1025,33 +1025,36 @@ class Level implements ChunkManager, Metadatable{
* @param Vector3 $pos * @param Vector3 $pos
*/ */
public function updateAround(Vector3 $pos){ public function updateAround(Vector3 $pos){
$pos = $pos->floor(); $x = (int) floor($pos->x);
$this->server->getPluginManager()->callEvent($ev = new BlockUpdateEvent($this->getBlock($this->temporalVector->setComponents($pos->x, $pos->y - 1, $pos->z)))); $y = (int) floor($pos->y);
$z = (int) floor($pos->z);
$this->server->getPluginManager()->callEvent($ev = new BlockUpdateEvent($this->getBlockAt($x, $y - 1, $z)));
if(!$ev->isCancelled()){ if(!$ev->isCancelled()){
$ev->getBlock()->onUpdate(self::BLOCK_UPDATE_NORMAL); $ev->getBlock()->onUpdate(self::BLOCK_UPDATE_NORMAL);
} }
$this->server->getPluginManager()->callEvent($ev = new BlockUpdateEvent($this->getBlock($this->temporalVector->setComponents($pos->x, $pos->y + 1, $pos->z)))); $this->server->getPluginManager()->callEvent($ev = new BlockUpdateEvent($this->getBlockAt($x, $y + 1, $z)));
if(!$ev->isCancelled()){ if(!$ev->isCancelled()){
$ev->getBlock()->onUpdate(self::BLOCK_UPDATE_NORMAL); $ev->getBlock()->onUpdate(self::BLOCK_UPDATE_NORMAL);
} }
$this->server->getPluginManager()->callEvent($ev = new BlockUpdateEvent($this->getBlock($this->temporalVector->setComponents($pos->x - 1, $pos->y, $pos->z)))); $this->server->getPluginManager()->callEvent($ev = new BlockUpdateEvent($this->getBlockAt($x - 1, $y, $z)));
if(!$ev->isCancelled()){ if(!$ev->isCancelled()){
$ev->getBlock()->onUpdate(self::BLOCK_UPDATE_NORMAL); $ev->getBlock()->onUpdate(self::BLOCK_UPDATE_NORMAL);
} }
$this->server->getPluginManager()->callEvent($ev = new BlockUpdateEvent($this->getBlock($this->temporalVector->setComponents($pos->x + 1, $pos->y, $pos->z)))); $this->server->getPluginManager()->callEvent($ev = new BlockUpdateEvent($this->getBlockAt($x + 1, $y, $z)));
if(!$ev->isCancelled()){ if(!$ev->isCancelled()){
$ev->getBlock()->onUpdate(self::BLOCK_UPDATE_NORMAL); $ev->getBlock()->onUpdate(self::BLOCK_UPDATE_NORMAL);
} }
$this->server->getPluginManager()->callEvent($ev = new BlockUpdateEvent($this->getBlock($this->temporalVector->setComponents($pos->x, $pos->y, $pos->z - 1)))); $this->server->getPluginManager()->callEvent($ev = new BlockUpdateEvent($this->getBlockAt($x, $y, $z - 1)));
if(!$ev->isCancelled()){ if(!$ev->isCancelled()){
$ev->getBlock()->onUpdate(self::BLOCK_UPDATE_NORMAL); $ev->getBlock()->onUpdate(self::BLOCK_UPDATE_NORMAL);
} }
$this->server->getPluginManager()->callEvent($ev = new BlockUpdateEvent($this->getBlock($this->temporalVector->setComponents($pos->x, $pos->y, $pos->z + 1)))); $this->server->getPluginManager()->callEvent($ev = new BlockUpdateEvent($this->getBlockAt($x, $y, $z + 1)));
if(!$ev->isCancelled()){ if(!$ev->isCancelled()){
$ev->getBlock()->onUpdate(self::BLOCK_UPDATE_NORMAL); $ev->getBlock()->onUpdate(self::BLOCK_UPDATE_NORMAL);
} }
@ -1123,7 +1126,7 @@ class Level implements ChunkManager, Metadatable{
for($z = $minZ; $z <= $maxZ; ++$z){ for($z = $minZ; $z <= $maxZ; ++$z){
for($x = $minX; $x <= $maxX; ++$x){ for($x = $minX; $x <= $maxX; ++$x){
for($y = $minY; $y <= $maxY; ++$y){ for($y = $minY; $y <= $maxY; ++$y){
$block = $this->getBlock($this->temporalVector->setComponents($x, $y, $z)); $block = $this->getBlockAt($x, $y, $z);
if($block->getId() !== 0 and $block->collidesWithBB($bb)){ if($block->getId() !== 0 and $block->collidesWithBB($bb)){
return [$block]; return [$block];
} }
@ -1134,7 +1137,7 @@ class Level implements ChunkManager, Metadatable{
for($z = $minZ; $z <= $maxZ; ++$z){ for($z = $minZ; $z <= $maxZ; ++$z){
for($x = $minX; $x <= $maxX; ++$x){ for($x = $minX; $x <= $maxX; ++$x){
for($y = $minY; $y <= $maxY; ++$y){ for($y = $minY; $y <= $maxY; ++$y){
$block = $this->getBlock($this->temporalVector->setComponents($x, $y, $z)); $block = $this->getBlockAt($x, $y, $z);
if($block->getId() !== 0 and $block->collidesWithBB($bb)){ if($block->getId() !== 0 and $block->collidesWithBB($bb)){
$collides[] = $block; $collides[] = $block;
} }
@ -1186,7 +1189,7 @@ class Level implements ChunkManager, Metadatable{
for($z = $minZ; $z <= $maxZ; ++$z){ for($z = $minZ; $z <= $maxZ; ++$z){
for($x = $minX; $x <= $maxX; ++$x){ for($x = $minX; $x <= $maxX; ++$x){
for($y = $minY; $y <= $maxY; ++$y){ for($y = $minY; $y <= $maxY; ++$y){
$block = $this->getBlock($this->temporalVector->setComponents($x, $y, $z)); $block = $this->getBlockAt($x, $y, $z);
if(!$block->canPassThrough() and $block->collidesWithBB($bb)){ if(!$block->canPassThrough() and $block->collidesWithBB($bb)){
foreach($block->getCollisionBoxes() as $blockBB){ foreach($block->getCollisionBoxes() as $blockBB){
$collides[] = $blockBB; $collides[] = $blockBB;
@ -1311,10 +1314,11 @@ class Level implements ChunkManager, Metadatable{
} }
/** /**
* Gets the Block object at the Vector3 location * Gets the Block object at the Vector3 location. This method wraps around {@link getBlockAt}, converting the
* vector components to integers.
* *
* Note for plugin developers: If you are using this method a lot (thousands of times for many positions for * Note: If you're using this for performance-sensitive code, and you're guaranteed to be supplying ints in the
* example), you may want to set addToCache to false to avoid using excessive amounts of memory. * specified vector, consider using {@link getBlockAt} instead for better performance.
* *
* @param Vector3 $pos * @param Vector3 $pos
* @param bool $cached Whether to use the block cache for getting the block (faster, but may be inaccurate) * @param bool $cached Whether to use the block cache for getting the block (faster, but may be inaccurate)
@ -1323,25 +1327,41 @@ class Level implements ChunkManager, Metadatable{
* @return Block * @return Block
*/ */
public function getBlock(Vector3 $pos, bool $cached = true, bool $addToCache = true) : Block{ public function getBlock(Vector3 $pos, bool $cached = true, bool $addToCache = true) : Block{
$pos = $pos->floor(); return $this->getBlockAt((int) floor($pos->x), (int) floor($pos->y), (int) floor($pos->z), $cached, $addToCache);
}
/**
* Gets the Block object at the specified coordinates.
*
* Note for plugin developers: If you are using this method a lot (thousands of times for many positions for
* example), you may want to set addToCache to false to avoid using excessive amounts of memory.
*
* @param int $x
* @param int $y
* @param int $z
* @param bool $cached Whether to use the block cache for getting the block (faster, but may be inaccurate)
* @param bool $addToCache Whether to cache the block object created by this method call.
*
* @return Block
*/
public function getBlockAt(int $x, int $y, int $z, bool $cached = true, bool $addToCache = true) : Block{
$fullState = 0; $fullState = 0;
$index = null; $index = null;
if($this->isInWorld($pos->x, $pos->y, $pos->z)){ if($this->isInWorld($x, $y, $z)){
$index = Level::blockHash($pos->x, $pos->y, $pos->z); $index = Level::blockHash($x, $y, $z);
if($cached and isset($this->blockCache[$index])){ if($cached and isset($this->blockCache[$index])){
return $this->blockCache[$index]; return $this->blockCache[$index];
}elseif(isset($this->chunks[$chunkIndex = Level::chunkHash($pos->x >> 4, $pos->z >> 4)])){ }elseif(isset($this->chunks[$chunkIndex = Level::chunkHash($x >> 4, $z >> 4)])){
$fullState = $this->chunks[$chunkIndex]->getFullBlock($pos->x & 0x0f, $pos->y, $pos->z & 0x0f); $fullState = $this->chunks[$chunkIndex]->getFullBlock($x & 0x0f, $y, $z & 0x0f);
} }
} }
$block = clone $this->blockStates[$fullState & 0xfff]; $block = clone $this->blockStates[$fullState & 0xfff];
$block->x = $pos->x; $block->x = $x;
$block->y = $pos->y; $block->y = $y;
$block->z = $pos->z; $block->z = $z;
$block->level = $this; $block->level = $this;
if($addToCache and $index !== null){ if($addToCache and $index !== null){
@ -1656,7 +1676,7 @@ class Level implements ChunkManager, Metadatable{
$drops = $target->getDrops($item); //Fixes tile entities being deleted before getting drops $drops = $target->getDrops($item); //Fixes tile entities being deleted before getting drops
} }
$above = $this->getBlock(new Vector3($target->x, $target->y + 1, $target->z)); $above = $this->getBlockAt($target->x, $target->y + 1, $target->z);
if($above->getId() === Block::FIRE){ //TODO: this should be done in Fire's onUpdate(), not with this hack if($above->getId() === Block::FIRE){ //TODO: this should be done in Fire's onUpdate(), not with this hack
$this->setBlock($above, BlockFactory::get(Block::AIR), true); $this->setBlock($above, BlockFactory::get(Block::AIR), true);
} }

View File

@ -226,7 +226,7 @@ abstract class Tile extends Position{
* @return Block * @return Block
*/ */
public function getBlock() : Block{ public function getBlock() : Block{
return $this->level->getBlock($this); return $this->level->getBlockAt($this->x, $this->y, $this->z);
} }
/** /**