mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-07-19 09:26:45 +00:00
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:
parent
c41ac7b0a2
commit
4c30b6b8a1
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
@ -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))));
|
||||
$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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user