Optimized Liquid spreading, optimized light updates, improved side block get/update, fixed raw set not cleaning Block cache (TNT explosions)

This commit is contained in:
Shoghi Cervantes 2014-12-10 00:35:36 +01:00
parent c41ac7b0a2
commit 4c30b6b8a1
3 changed files with 98 additions and 54 deletions

View File

@ -760,6 +760,9 @@ class Block extends Position implements Metadatable{
} }
}else{ }else{
self::$lightFilter[$id] = 1; 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 * @return Block
*/ */
public function getSide($side, $step = 1){ public function getSide($side, $step = 1){
$v = parent::getSide($side, $step);
if($this->isValid()){ 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));
} }
/** /**

View File

@ -29,6 +29,9 @@ use pocketmine\math\Vector3;
abstract class Liquid extends Transparent{ abstract class Liquid extends Transparent{
/** @var Vector3 */
private $temporalVector = null;
public function hasEntityCollision(){ public function hasEntityCollision(){
return true; return true;
} }
@ -91,6 +94,10 @@ abstract class Liquid extends Transparent{
public function getFlowVector(){ public function getFlowVector(){
$vector = new Vector3(0, 0, 0); $vector = new Vector3(0, 0, 0);
if($this->temporalVector === null){
$this->temporalVector = new Vector3(0, 0, 0);
}
$decay = $this->getEffectiveFlowDecay($this); $decay = $this->getEffectiveFlowDecay($this);
for($j = 0; $j < 4; ++$j){ for($j = 0; $j < 4; ++$j){
@ -108,7 +115,7 @@ abstract class Liquid extends Transparent{
}elseif($j === 3){ }elseif($j === 3){
++$z; ++$z;
} }
$sideBlock = $this->getLevel()->getBlock(new Vector3($x, $y, $z)); $sideBlock = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z));
$blockDecay = $this->getEffectiveFlowDecay($sideBlock); $blockDecay = $this->getEffectiveFlowDecay($sideBlock);
if($blockDecay < 0){ if($blockDecay < 0){
@ -116,38 +123,42 @@ abstract class Liquid extends Transparent{
continue; continue;
} }
$blockDecay = $this->getEffectiveFlowDecay($sideBlock->getSide(0)); $blockDecay = $this->getEffectiveFlowDecay($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z)));
if($blockDecay >= 0){ if($blockDecay >= 0){
$realDecay = $blockDecay - ($decay - 8); $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; continue;
}else{ }else{
$realDecay = $blockDecay - $decay; $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){ if($this->getDamage() >= 8){
$falling = false; $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; $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; $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; $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; $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; $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; $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; $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; $falling = true;
} }
@ -181,6 +192,10 @@ abstract class Liquid extends Transparent{
$this->checkForHarden(); $this->checkForHarden();
$this->getLevel()->scheduleUpdate($this, $this->tickRate()); $this->getLevel()->scheduleUpdate($this, $this->tickRate());
}elseif($type === Level::BLOCK_UPDATE_SCHEDULED){ }elseif($type === Level::BLOCK_UPDATE_SCHEDULED){
if($this->temporalVector === null){
$this->temporalVector = new Vector3(0, 0, 0);
}
$decay = $this->getFlowDecay($this); $decay = $this->getFlowDecay($this);
$multiplier = $this instanceof Lava ? 2 : 1; $multiplier = $this instanceof Lava ? 2 : 1;
@ -189,10 +204,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->getSide(4), $smallestFlowDecay); $smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1)), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($this->getSide(5), $smallestFlowDecay); $smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1)), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($this->getSide(2), $smallestFlowDecay); $smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z)), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($this->getSide(3), $smallestFlowDecay); $smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z)), $smallestFlowDecay);
$k = $smallestFlowDecay + $multiplier; $k = $smallestFlowDecay + $multiplier;
@ -200,7 +215,7 @@ abstract class Liquid extends Transparent{
$k = -1; $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){ if($topFlowDecay >= 8){
$k = $topFlowDecay; $k = $topFlowDecay;
}else{ }else{
@ -209,7 +224,7 @@ abstract class Liquid extends Transparent{
} }
if($this->adjacentSources >= 2 and $this instanceof Water){ 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()){ if($bottomBlock->isSolid()){
$k = 0; $k = 0;
}elseif($bottomBlock instanceof Water and $bottomBlock->getDamage() === 0){ }elseif($bottomBlock instanceof Water and $bottomBlock->getDamage() === 0){
@ -225,7 +240,7 @@ abstract class Liquid extends Transparent{
if($k !== $decay){ if($k !== $decay){
$decay = $k; $decay = $k;
if($decay < 0){ if($decay < 0){
$this->getLevel()->setBlock($this, Block::get(Item::AIR), true); $this->getLevel()->setBlock($this, new Air(), true);
}else{ }else{
$this->getLevel()->setBlock($this, Block::get($this->id, $decay), true); $this->getLevel()->setBlock($this, Block::get($this->id, $decay), true);
$this->getLevel()->scheduleUpdate($this, $this->tickRate()); $this->getLevel()->scheduleUpdate($this, $this->tickRate());
@ -238,7 +253,7 @@ abstract class Liquid extends Transparent{
//$this->updateFlow(); //$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($bottomBlock->canBeFlowedInto() or $bottomBlock instanceof Liquid){
if($this instanceof Lava and $bottomBlock instanceof Water){ if($this instanceof Lava and $bottomBlock instanceof Water){
@ -268,19 +283,19 @@ abstract class Liquid extends Transparent{
} }
if($flags[0]){ 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]){ 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]){ 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]){ 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){ }elseif($j === 3){
++$z; ++$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)){ 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($blockSide->getSide(0)->canBeFlowedInto()){ }elseif($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z))->canBeFlowedInto()){
return $accumulatedCost; return $accumulatedCost;
} }
@ -349,6 +364,10 @@ abstract class Liquid extends Transparent{
} }
private function getOptimalFlowDirections(){ private function getOptimalFlowDirections(){
if($this->temporalVector === null){
$this->temporalVector = new Vector3(0, 0, 0);
}
for($j = 0; $j < 4; ++$j){ for($j = 0; $j < 4; ++$j){
$this->flowCost[$j] = 1000; $this->flowCost[$j] = 1000;
@ -365,13 +384,13 @@ abstract class Liquid extends Transparent{
}elseif($j === 3){ }elseif($j === 3){
++$z; ++$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)){ 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($block->getSide(0)->canBeFlowedInto()){ }elseif($this->getLevel()->getBlock($this->temporalVector->setComponents($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

@ -183,6 +183,9 @@ class Level implements ChunkManager, Metadatable{
/** @var Vector3 */ /** @var Vector3 */
private $temporalVector; private $temporalVector;
/** @var \SplFixedArray */
private $blockStates;
protected $chunkTickRadius; protected $chunkTickRadius;
protected $chunkTickList = []; protected $chunkTickList = [];
protected $chunksPerTick; protected $chunksPerTick;
@ -267,6 +270,7 @@ class Level implements ChunkManager, Metadatable{
* @throws \Exception * @throws \Exception
*/ */
public function __construct(Server $server, $name, $path, $provider){ public function __construct(Server $server, $name, $path, $provider){
$this->blockStates = Block::$fullList;
$this->levelId = static::$levelIdCounter++; $this->levelId = static::$levelIdCounter++;
$this->blockMetadata = new BlockMetadataStore($this); $this->blockMetadata = new BlockMetadataStore($this);
$this->server = $server; $this->server = $server;
@ -720,11 +724,34 @@ class Level implements ChunkManager, Metadatable{
* @param Vector3 $pos * @param Vector3 $pos
*/ */
public function updateAround(Vector3 $pos){ public function updateAround(Vector3 $pos){
for($side = 0; $side <= 5; ++$side){ $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->getBlock($pos->getSide($side)))); 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))));
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 * @return Block
*/ */
public function getBlock(Vector3 $pos, $cached = true){ public function getBlock(Vector3 $pos, $cached = true){
$fullState = 0;
$index = Level::blockHash($pos->x, $pos->y, $pos->z); $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]; return $this->blockCache[$index];
}elseif($pos->y >= 0 and $pos->y < 128 and ($chunk = $this->getChunk($pos->x >> 4, $pos->z >> 4, false)) !== null){ }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, $pos->z & 0x0f); $fullState = $chunk->getFullBlock($pos->x & 0x0f, $pos->y & 0x7f, $pos->z & 0x0f);
}else{
$fullState = 0;
} }
$block = Block::$fullList[$fullState]; $block = clone $this->blockStates[$fullState];
if($block !== null){
$block = new $block($fullState & 0x0f);
}else{
$block = new Block($fullState >> 4, $fullState & 0x0f);
}
$block->x = $pos->x; $block->x = $pos->x;
$block->y = $pos->y; $block->y = $pos->y;
@ -975,10 +998,10 @@ class Level implements ChunkManager, Metadatable{
$this->setBlockLightAt($x, $y, $z, $newLevel); $this->setBlockLightAt($x, $y, $z, $newLevel);
if($newLevel < $oldLevel){ if($newLevel < $oldLevel){
$removalVisited["$x:$y:$z"] = true; $removalVisited[Level::blockHash($x, $y, $z)] = true;
$lightRemovalQueue->enqueue([new Vector3($x, $y, $z), $oldLevel]); $lightRemovalQueue->enqueue([new Vector3($x, $y, $z), $oldLevel]);
}else{ }else{
$visited["$x:$y:$z"] = true; $visited[Level::blockHash($x, $y, $z)] = true;
$lightPropagationQueue->enqueue(new Vector3($x, $y, $z)); $lightPropagationQueue->enqueue(new Vector3($x, $y, $z));
} }
} }
@ -1020,14 +1043,14 @@ class Level implements ChunkManager, Metadatable{
if($current !== 0 and $current < $currentLight){ if($current !== 0 and $current < $currentLight){
$this->setBlockLightAt($x, $y, $z, 0); $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; $visited[$index] = true;
if($current > 1){ if($current > 1){
$queue->enqueue([new Vector3($x, $y, $z), $current]); $queue->enqueue([new Vector3($x, $y, $z), $current]);
} }
} }
}elseif($current >= $currentLight){ }elseif($current >= $currentLight){
if(!isset($spreadVisited[$index = "$x:$y:$z"])){ if(!isset($spreadVisited[$index = Level::blockHash($x, $y, $z)])){
$spreadVisited[$index] = true; $spreadVisited[$index] = true;
$spreadQueue->enqueue(new Vector3($x, $y, $z)); $spreadQueue->enqueue(new Vector3($x, $y, $z));
} }
@ -1040,7 +1063,7 @@ class Level implements ChunkManager, Metadatable{
if($current < $currentLight){ if($current < $currentLight){
$this->setBlockLightAt($x, $y, $z, $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; $visited[$index] = true;
if($currentLight > 1){ if($currentLight > 1){
$queue->enqueue(new Vector3($x, $y, $z)); $queue->enqueue(new Vector3($x, $y, $z));
@ -1072,7 +1095,7 @@ class Level implements ChunkManager, Metadatable{
return false; 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($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)){ if(!($pos instanceof Position)){
@ -1558,7 +1581,7 @@ class Level implements ChunkManager, Metadatable{
* @param int $id 0-255 * @param int $id 0-255
*/ */
public function setBlockIdAt($x, $y, $z, $id){ 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); $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 * @param int $data 0-15
*/ */
public function setBlockDataAt($x, $y, $z, $data){ 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); $this->getChunk($x >> 4, $z >> 4, true)->setBlockData($x & 0x0f, $y & 0x7f, $z & 0x0f, $data & 0x0f);
} }