diff --git a/src/pocketmine/block/Block.php b/src/pocketmine/block/Block.php index a5b79dae9..a8d47318d 100644 --- a/src/pocketmine/block/Block.php +++ b/src/pocketmine/block/Block.php @@ -760,6 +760,9 @@ class Block extends Position implements Metadatable{ } }else{ self::$lightFilter[$id] = 1; + for($data = 0; $data < 16; ++$data){ + self::$fullList[($id << 4) | $data] = new Block($id, $data); + } } } } @@ -1019,12 +1022,11 @@ class Block extends Position implements Metadatable{ * @return Block */ public function getSide($side, $step = 1){ - $v = parent::getSide($side, $step); if($this->isValid()){ - return $this->getLevel()->getBlock($v); + return $this->getLevel()->getBlock(Vector3::getSide($side, $step)); } - return Block::get(Item::AIR, 0, $v); + return Block::get(Item::AIR, 0, new Position($v->x, $v->y, $v->z, null)); } /** diff --git a/src/pocketmine/block/Liquid.php b/src/pocketmine/block/Liquid.php index ca5c1712b..092d66c38 100644 --- a/src/pocketmine/block/Liquid.php +++ b/src/pocketmine/block/Liquid.php @@ -29,6 +29,9 @@ use pocketmine\math\Vector3; abstract class Liquid extends Transparent{ + /** @var Vector3 */ + private $temporalVector = null; + public function hasEntityCollision(){ return true; } @@ -91,6 +94,10 @@ abstract class Liquid extends Transparent{ public function getFlowVector(){ $vector = new Vector3(0, 0, 0); + if($this->temporalVector === null){ + $this->temporalVector = new Vector3(0, 0, 0); + } + $decay = $this->getEffectiveFlowDecay($this); for($j = 0; $j < 4; ++$j){ @@ -108,7 +115,7 @@ abstract class Liquid extends Transparent{ }elseif($j === 3){ ++$z; } - $sideBlock = $this->getLevel()->getBlock(new Vector3($x, $y, $z)); + $sideBlock = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z)); $blockDecay = $this->getEffectiveFlowDecay($sideBlock); if($blockDecay < 0){ @@ -116,38 +123,42 @@ abstract class Liquid extends Transparent{ continue; } - $blockDecay = $this->getEffectiveFlowDecay($sideBlock->getSide(0)); + $blockDecay = $this->getEffectiveFlowDecay($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z))); if($blockDecay >= 0){ $realDecay = $blockDecay - ($decay - 8); - $vector = $vector->add(($sideBlock->x - $this->x) * $realDecay, ($sideBlock->y - $this->y) * $realDecay, ($sideBlock->z - $this->z) * $realDecay); + $vector->x += ($sideBlock->x - $this->x) * $realDecay; + $vector->y += ($sideBlock->y - $this->y) * $realDecay; + $vector->z += ($sideBlock->z - $this->z) * $realDecay; } continue; }else{ $realDecay = $blockDecay - $decay; - $vector = $vector->add(($sideBlock->x - $this->x) * $realDecay, ($sideBlock->y - $this->y) * $realDecay, ($sideBlock->z - $this->z) * $realDecay); + $vector->x += ($sideBlock->x - $this->x) * $realDecay; + $vector->y += ($sideBlock->y - $this->y) * $realDecay; + $vector->z += ($sideBlock->z - $this->z) * $realDecay; } } if($this->getDamage() >= 8){ $falling = false; - if(!$this->getLevel()->getBlock($this->add(0, 0, -1))->canBeFlowedInto()){ + if(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1))->canBeFlowedInto()){ $falling = true; - }elseif(!$this->getLevel()->getBlock($this->add(0, 0, 1))->canBeFlowedInto()){ + }elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1))->canBeFlowedInto()){ $falling = true; - }elseif(!$this->getLevel()->getBlock($this->add(-1, 0, 0))->canBeFlowedInto()){ + }elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z))->canBeFlowedInto()){ $falling = true; - }elseif(!$this->getLevel()->getBlock($this->add(1, 0, 0))->canBeFlowedInto()){ + }elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z))->canBeFlowedInto()){ $falling = true; - }elseif(!$this->getLevel()->getBlock($this->add(0, 1, -1))->canBeFlowedInto()){ + }elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z - 1))->canBeFlowedInto()){ $falling = true; - }elseif(!$this->getLevel()->getBlock($this->add(0, 1, 1))->canBeFlowedInto()){ + }elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z + 1))->canBeFlowedInto()){ $falling = true; - }elseif(!$this->getLevel()->getBlock($this->add(-1, 1, 0))->canBeFlowedInto()){ + }elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y + 1, $this->z))->canBeFlowedInto()){ $falling = true; - }elseif(!$this->getLevel()->getBlock($this->add(1, 1, 0))->canBeFlowedInto()){ + }elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y + 1, $this->z))->canBeFlowedInto()){ $falling = true; } @@ -181,6 +192,10 @@ abstract class Liquid extends Transparent{ $this->checkForHarden(); $this->getLevel()->scheduleUpdate($this, $this->tickRate()); }elseif($type === Level::BLOCK_UPDATE_SCHEDULED){ + if($this->temporalVector === null){ + $this->temporalVector = new Vector3(0, 0, 0); + } + $decay = $this->getFlowDecay($this); $multiplier = $this instanceof Lava ? 2 : 1; @@ -189,10 +204,10 @@ abstract class Liquid extends Transparent{ if($decay > 0){ $smallestFlowDecay = -100; $this->adjacentSources = 0; - $smallestFlowDecay = $this->getSmallestFlowDecay($this->getSide(4), $smallestFlowDecay); - $smallestFlowDecay = $this->getSmallestFlowDecay($this->getSide(5), $smallestFlowDecay); - $smallestFlowDecay = $this->getSmallestFlowDecay($this->getSide(2), $smallestFlowDecay); - $smallestFlowDecay = $this->getSmallestFlowDecay($this->getSide(3), $smallestFlowDecay); + $smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($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->getBlock($this->temporalVector->setComponents($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); $k = $smallestFlowDecay + $multiplier; @@ -200,7 +215,7 @@ abstract class Liquid extends Transparent{ $k = -1; } - if(($topFlowDecay = $this->getFlowDecay($this->getSide(1))) >= 0){ + if(($topFlowDecay = $this->getFlowDecay($this->level->getBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z))))) >= 0){ if($topFlowDecay >= 8){ $k = $topFlowDecay; }else{ @@ -209,7 +224,7 @@ abstract class Liquid extends Transparent{ } if($this->adjacentSources >= 2 and $this instanceof Water){ - $bottomBlock = $this->getSide(0); + $bottomBlock = $this->level->getBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y - 1, $this->z))); if($bottomBlock->isSolid()){ $k = 0; }elseif($bottomBlock instanceof Water and $bottomBlock->getDamage() === 0){ @@ -225,7 +240,7 @@ abstract class Liquid extends Transparent{ if($k !== $decay){ $decay = $k; if($decay < 0){ - $this->getLevel()->setBlock($this, Block::get(Item::AIR), true); + $this->getLevel()->setBlock($this, new Air(), true); }else{ $this->getLevel()->setBlock($this, Block::get($this->id, $decay), true); $this->getLevel()->scheduleUpdate($this, $this->tickRate()); @@ -238,7 +253,7 @@ abstract class Liquid extends Transparent{ //$this->updateFlow(); } - $bottomBlock = $this->getSide(0); + $bottomBlock = $this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y - 1, $this->z)); if($bottomBlock->canBeFlowedInto() or $bottomBlock instanceof Liquid){ if($this instanceof Lava and $bottomBlock instanceof Water){ @@ -268,19 +283,19 @@ abstract class Liquid extends Transparent{ } if($flags[0]){ - $this->flowIntoBlock($this->getSide(4), $l); + $this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z)), $l); } if($flags[1]){ - $this->flowIntoBlock($this->getSide(5), $l); + $this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z)), $l); } if($flags[2]){ - $this->flowIntoBlock($this->getSide(2), $l); + $this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1)), $l); } if($flags[3]){ - $this->flowIntoBlock($this->getSide(3), $l); + $this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1)), $l); } } @@ -323,13 +338,13 @@ abstract class Liquid extends Transparent{ }elseif($j === 3){ ++$z; } - $blockSide = $this->getLevel()->getBlock(new Vector3($x, $y, $z)); + $blockSide = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z)); if(!$blockSide->canBeFlowedInto() and !($blockSide instanceof Liquid)){ continue; }elseif($blockSide instanceof Liquid and $blockSide->getDamage() === 0){ continue; - }elseif($blockSide->getSide(0)->canBeFlowedInto()){ + }elseif($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z))->canBeFlowedInto()){ return $accumulatedCost; } @@ -349,6 +364,10 @@ abstract class Liquid extends Transparent{ } private function getOptimalFlowDirections(){ + if($this->temporalVector === null){ + $this->temporalVector = new Vector3(0, 0, 0); + } + for($j = 0; $j < 4; ++$j){ $this->flowCost[$j] = 1000; @@ -365,13 +384,13 @@ abstract class Liquid extends Transparent{ }elseif($j === 3){ ++$z; } - $block = $this->getLevel()->getBlock(new Vector3($x, $y, $z)); + $block = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z)); if(!$block->canBeFlowedInto() and !($block instanceof Liquid)){ continue; }elseif($block instanceof Liquid and $block->getDamage() === 0){ continue; - }elseif($block->getSide(0)->canBeFlowedInto()){ + }elseif($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z))->canBeFlowedInto()){ $this->flowCost[$j] = 0; }else{ $this->flowCost[$j] = $this->calculateFlowCost($block, 1, $j); diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 7962d82ba..2b7e19395 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -183,6 +183,9 @@ class Level implements ChunkManager, Metadatable{ /** @var Vector3 */ private $temporalVector; + /** @var \SplFixedArray */ + private $blockStates; + protected $chunkTickRadius; protected $chunkTickList = []; protected $chunksPerTick; @@ -267,6 +270,7 @@ class Level implements ChunkManager, Metadatable{ * @throws \Exception */ public function __construct(Server $server, $name, $path, $provider){ + $this->blockStates = Block::$fullList; $this->levelId = static::$levelIdCounter++; $this->blockMetadata = new BlockMetadataStore($this); $this->server = $server; @@ -720,11 +724,34 @@ class Level implements ChunkManager, Metadatable{ * @param Vector3 $pos */ public function updateAround(Vector3 $pos){ - for($side = 0; $side <= 5; ++$side){ - $this->server->getPluginManager()->callEvent($ev = new BlockUpdateEvent($this->getBlock($pos->getSide($side)))); - if(!$ev->isCancelled()){ - $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)))); + if(!$ev->isCancelled()){ + $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)))); + if(!$ev->isCancelled()){ + $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)))); + if(!$ev->isCancelled()){ + $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)))); + if(!$ev->isCancelled()){ + $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)))); + if(!$ev->isCancelled()){ + $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)))); + if(!$ev->isCancelled()){ + $ev->getBlock()->onUpdate(self::BLOCK_UPDATE_NORMAL); } } @@ -930,20 +957,16 @@ class Level implements ChunkManager, Metadatable{ * @return Block */ public function getBlock(Vector3 $pos, $cached = true){ - $fullState = 0; $index = Level::blockHash($pos->x, $pos->y, $pos->z); - if($cached and isset($this->blockCache[$index])){ + if($cached === true and isset($this->blockCache[$index])){ return $this->blockCache[$index]; - }elseif($pos->y >= 0 and $pos->y < 128 and ($chunk = $this->getChunk($pos->x >> 4, $pos->z >> 4, false)) !== null){ - $fullState = $chunk->getFullBlock($pos->x & 0x0f, $pos->y, $pos->z & 0x0f); + }elseif($pos->y >= 0 and $pos->y < 128 and ($chunk = $this->getChunk($pos->x >> 4, $pos->z >> 4)) !== null){ + $fullState = $chunk->getFullBlock($pos->x & 0x0f, $pos->y & 0x7f, $pos->z & 0x0f); + }else{ + $fullState = 0; } - $block = Block::$fullList[$fullState]; - if($block !== null){ - $block = new $block($fullState & 0x0f); - }else{ - $block = new Block($fullState >> 4, $fullState & 0x0f); - } + $block = clone $this->blockStates[$fullState]; $block->x = $pos->x; $block->y = $pos->y; @@ -975,10 +998,10 @@ class Level implements ChunkManager, Metadatable{ $this->setBlockLightAt($x, $y, $z, $newLevel); if($newLevel < $oldLevel){ - $removalVisited["$x:$y:$z"] = true; + $removalVisited[Level::blockHash($x, $y, $z)] = true; $lightRemovalQueue->enqueue([new Vector3($x, $y, $z), $oldLevel]); }else{ - $visited["$x:$y:$z"] = true; + $visited[Level::blockHash($x, $y, $z)] = true; $lightPropagationQueue->enqueue(new Vector3($x, $y, $z)); } } @@ -1020,14 +1043,14 @@ class Level implements ChunkManager, Metadatable{ if($current !== 0 and $current < $currentLight){ $this->setBlockLightAt($x, $y, $z, 0); - if(!isset($visited[$index = "$x:$y:$z"])){ + if(!isset($visited[$index = Level::blockHash($x, $y, $z)])){ $visited[$index] = true; if($current > 1){ $queue->enqueue([new Vector3($x, $y, $z), $current]); } } }elseif($current >= $currentLight){ - if(!isset($spreadVisited[$index = "$x:$y:$z"])){ + if(!isset($spreadVisited[$index = Level::blockHash($x, $y, $z)])){ $spreadVisited[$index] = true; $spreadQueue->enqueue(new Vector3($x, $y, $z)); } @@ -1040,7 +1063,7 @@ class Level implements ChunkManager, Metadatable{ if($current < $currentLight){ $this->setBlockLightAt($x, $y, $z, $currentLight); - if(!isset($visited[$index = "$x:$y:$z"])){ + if(!isset($visited[$index = Level::blockHash($x, $y, $z)])){ $visited[$index] = true; if($currentLight > 1){ $queue->enqueue(new Vector3($x, $y, $z)); @@ -1072,7 +1095,7 @@ class Level implements ChunkManager, Metadatable{ return false; } - unset($this->blockCache[Level::blockHash($pos->x, $pos->y, $pos->z)]); + unset($this->blockCache[$index = Level::blockHash($pos->x, $pos->y, $pos->z)]); if($this->getChunk($pos->x >> 4, $pos->z >> 4, true)->setBlock($pos->x & 0x0f, $pos->y & 0x7f, $pos->z & 0x0f, $block->getId(), $block->getDamage())){ if(!($pos instanceof Position)){ @@ -1558,7 +1581,7 @@ class Level implements ChunkManager, Metadatable{ * @param int $id 0-255 */ public function setBlockIdAt($x, $y, $z, $id){ - unset($this->blockCache["$x:$y:$z"]); + unset($this->blockCache[Level::blockHash($x, $y, $z)]); $this->getChunk($x >> 4, $z >> 4, true)->setBlockId($x & 0x0f, $y & 0x7f, $z & 0x0f, $id & 0xff); } @@ -1584,7 +1607,7 @@ class Level implements ChunkManager, Metadatable{ * @param int $data 0-15 */ public function setBlockDataAt($x, $y, $z, $data){ - unset($this->blockCache["$x:$y:$z"]); + unset($this->blockCache[Level::blockHash($x, $y, $z)]); $this->getChunk($x >> 4, $z >> 4, true)->setBlockData($x & 0x0f, $y & 0x7f, $z & 0x0f, $data & 0x0f); }