From 04ecbd1a76ec4a7134fbf3bce94ce48ca31077e1 Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Tue, 9 Dec 2014 14:36:16 +0100 Subject: [PATCH] Level optimization, added new chunk/block hashes --- src/pocketmine/Player.php | 3 +- src/pocketmine/block/Block.php | 4 + src/pocketmine/level/Explosion.php | 29 +++---- src/pocketmine/level/Level.php | 80 ++++++++++++------- src/pocketmine/level/format/anvil/Anvil.php | 7 +- .../level/format/mcregion/McRegion.php | 7 +- 6 files changed, 76 insertions(+), 54 deletions(-) diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 7fccc192b..f093cfef5 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -607,6 +607,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $X = null; $Z = null; Level::getXZ($index, $X, $Z); + if(!$this->level->isChunkPopulated($X, $Z)){ $this->level->generateChunk($X, $Z); if($this->spawned){ @@ -687,7 +688,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ for($Z = -$side; $Z <= $side; ++$Z){ $chunkX = $X + $centerX; $chunkZ = $Z + $centerZ; - if(!isset($this->usedChunks[$index = "$chunkX:$chunkZ"])){ + if(!isset($this->usedChunks[$index = Level::chunkHash($chunkX, $chunkZ)])){ $newOrder[$index] = abs($X) + abs($Z); }else{ $currentQueue[$index] = abs($X) + abs($Z); diff --git a/src/pocketmine/block/Block.php b/src/pocketmine/block/Block.php index b7450eeba..a5b79dae9 100644 --- a/src/pocketmine/block/Block.php +++ b/src/pocketmine/block/Block.php @@ -538,6 +538,8 @@ class Block extends Position implements Metadatable{ /** @var \SplFixedArray */ public static $solid = null; /** @var \SplFixedArray */ + public static $hardness = null; + /** @var \SplFixedArray */ public static $transparent = null; protected $id; @@ -579,6 +581,7 @@ class Block extends Position implements Metadatable{ self::$light = new \SplFixedArray(256); self::$lightFilter = new \SplFixedArray(256); self::$solid = new \SplFixedArray(256); + self::$hardness = new \SplFixedArray(256); self::$transparent = new \SplFixedArray(256); self::$list[self::AIR] = Air::class; self::$list[self::STONE] = Stone::class; @@ -739,6 +742,7 @@ class Block extends Position implements Metadatable{ self::$solid[$id] = $block->isSolid(); self::$transparent[$id] = $block->isTransparent(); + self::$hardness[$id] = $block->getHardness(); self::$light[$id] = $block->getLightLevel(); if($block->isSolid()){ diff --git a/src/pocketmine/level/Explosion.php b/src/pocketmine/level/Explosion.php index 95a88e232..fa4c3c634 100644 --- a/src/pocketmine/level/Explosion.php +++ b/src/pocketmine/level/Explosion.php @@ -83,25 +83,27 @@ class Explosion{ return false; } - $pointer = new Vector3(0, 0, 0); $vector = new Vector3(0, 0, 0); $vBlock = new Vector3(0, 0, 0); - $mRays = $this->rays - 1; + $mRays = intval($this->rays - 1); for($i = 0; $i < $this->rays; ++$i){ for($j = 0; $j < $this->rays; ++$j){ - //break 2 gets here for($k = 0; $k < $this->rays; ++$k){ - if($i == 0 or $i == $mRays or $j == 0 or $j == $mRays or $k == 0 or $k == $mRays){ + if($i === 0 or $i === $mRays or $j === 0 or $j === $mRays or $k === 0 or $k === $mRays){ $vector->setComponents($i / $mRays * 2 - 1, $j / $mRays * 2 - 1, $k / $mRays * 2 - 1); $vector->setComponents(($vector->x / ($len = $vector->length())) * $this->stepLen, ($vector->y / $len) * $this->stepLen, ($vector->z / $len) * $this->stepLen); - $pointer->setComponents($this->source->x, $this->source->y, $this->source->z); + $pointerX = $this->source->x; + $pointerY = $this->source->y; + $pointerZ = $this->source->z; for($blastForce = $this->size * (mt_rand(700, 1300) / 1000); $blastForce > 0; $blastForce -= $this->stepLen * 0.75){ - $x = (int) $pointer->x; - $y = (int) $pointer->y; - $z = (int) $pointer->z; - $vBlock->setComponents($pointer->x >= $x ? $x : $x - 1, $pointer->y >= $y ? $y : $y - 1, $pointer->z >= $z ? $z : $z - 1); + $x = (int) $pointerX; + $y = (int) $pointerY; + $z = (int) $pointerZ; + $vBlock->x = $pointerX >= $x ? $x : $x - 1; + $vBlock->y = $pointerY >= $y ? $y : $y - 1; + $vBlock->z = $pointerZ >= $z ? $z : $z - 1; if($vBlock->y < 0 or $vBlock->y > 127){ break; } @@ -110,15 +112,14 @@ class Explosion{ if($block->getId() !== 0){ $blastForce -= ($block->getHardness() / 5 + 0.3) * $this->stepLen; if($blastForce > 0){ - $index = ($block->x << 15) + ($block->z << 7) + $block->y; - if(!isset($this->affectedBlocks[$index])){ + if(!isset($this->affectedBlocks[$index = Level::blockHash($block->x, $block->y, $block->z)])){ $this->affectedBlocks[$index] = $block; } } } - $pointer->x += $vector->x; - $pointer->y += $vector->y; - $pointer->z += $vector->z; + $pointerX += $vector->x; + $pointerY += $vector->y; + $pointerZ += $vector->z; } } } diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index c939171fa..7962d82ba 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -225,13 +225,35 @@ class Level implements ChunkManager, Metadatable{ * @return string */ public static function chunkHash($x, $z){ - return $x . ":" . $z; + return PHP_INT_SIZE === 8 ? (($x & 0xFFFFFFFF) << 32) | ($z & 0xFFFFFFFF) : $x . ":" . $z; + } + + public static function blockHash($x, $y, $z){ + return PHP_INT_SIZE === 8 ? (($x & 0xFFFFFFF) << 35) | (($y & 0x7f) << 28) | ($z & 0xFFFFFFF) : $x . ":" . $y .":". $z; + } + + public static function getBlockXYZ($hash, &$x, &$y, &$z){ + if(PHP_INT_SIZE === 8){ + $x = ($hash >> 35) << 36 >> 36; + $y = (($hash >> 28) & 0x7f);// << 57 >> 57; //it's always positive + $z = ($hash & 0xFFFFFFF) << 36 >> 36; + }else{ + $hash = explode(":", $hash); + $x = (int) $hash[0]; + $y = (int) $hash[1]; + $z = (int) $hash[2]; + } } public static function getXZ($hash, &$x, &$z){ - list($x, $z) = explode(":", $hash); - $x = (int) $x; - $z = (int) $z; + if(PHP_INT_SIZE === 8){ + $x = ($hash >> 32) << 32 >> 32; + $z = ($hash & 0xFFFFFFFF) << 32 >> 32; + }else{ + $hash = explode(":", $hash); + $x = (int) $hash[0]; + $z = (int) $hash[1]; + } } /** @@ -393,7 +415,7 @@ class Level implements ChunkManager, Metadatable{ * @return Player[] */ public function getUsingChunk($X, $Z){ - return isset($this->usedChunks[$index = "$X:$Z"]) ? $this->usedChunks[$index] : []; + return isset($this->usedChunks[$index = Level::chunkHash($X, $Z)]) ? $this->usedChunks[$index] : []; } /** @@ -474,7 +496,7 @@ class Level implements ChunkManager, Metadatable{ $this->timings->doTickPending->startTiming(); while($this->updateQueue->count() > 0 and $this->updateQueue->current()["priority"] <= $currentTick){ $block = $this->getBlock($this->updateQueue->extract()["data"]); - unset($this->updateQueueIndex["{$block->x}:{$block->y}:{$block->z}"]); + unset($this->updateQueueIndex[Level::blockHash($block->x, $block->y, $block->z)]); $block->onUpdate(self::BLOCK_UPDATE_SCHEDULED); } $this->timings->doTickPending->stopTiming(); @@ -698,10 +720,8 @@ class Level implements ChunkManager, Metadatable{ * @param Vector3 $pos */ public function updateAround(Vector3 $pos){ - $block = $this->getBlock($pos); - for($side = 0; $side <= 5; ++$side){ - $this->server->getPluginManager()->callEvent($ev = new BlockUpdateEvent($block->getSide($side))); + $this->server->getPluginManager()->callEvent($ev = new BlockUpdateEvent($this->getBlock($pos->getSide($side)))); if(!$ev->isCancelled()){ $ev->getBlock()->onUpdate(self::BLOCK_UPDATE_NORMAL); } @@ -713,8 +733,7 @@ class Level implements ChunkManager, Metadatable{ * @param int $delay */ public function scheduleUpdate(Vector3 $pos, $delay){ - $index = "{$pos->x}:{$pos->y}:{$pos->z}"; - if(isset($this->updateQueueIndex[$index]) and $this->updateQueueIndex[$index] <= $delay){ + if(isset($this->updateQueueIndex[$index = Level::blockHash($pos->x, $pos->y, $pos->z)]) and $this->updateQueueIndex[$index] <= $delay){ return; } $this->updateQueueIndex[$index] = $delay; @@ -912,7 +931,7 @@ class Level implements ChunkManager, Metadatable{ */ public function getBlock(Vector3 $pos, $cached = true){ $fullState = 0; - $index = PHP_INT_SIZE === 8 ? (($pos->x & 0xFFFFFFF) << 35) | (($pos->y & 0x7f) << 28) | ($pos->z & 0xFFFFFFF) : "{$pos->x}:{$pos->y}:{$pos->z}"; + $index = Level::blockHash($pos->x, $pos->y, $pos->z); if($cached 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){ @@ -1053,7 +1072,7 @@ class Level implements ChunkManager, Metadatable{ return false; } - unset($this->blockCache["{$pos->x}:{$pos->y}:{$pos->z}"]); + unset($this->blockCache[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)){ @@ -1094,7 +1113,6 @@ class Level implements ChunkManager, Metadatable{ if($update === true){ $this->updateAllLight($block); - $this->updateAround($pos); $this->server->getPluginManager()->callEvent($ev = new BlockUpdateEvent($block)); if(!$ev->isCancelled()){ $ev->getBlock()->onUpdate(self::BLOCK_UPDATE_NORMAL); @@ -1102,6 +1120,8 @@ class Level implements ChunkManager, Metadatable{ $entity->scheduleUpdate(); } } + + $this->updateAround($pos); } } } @@ -2067,22 +2087,24 @@ class Level implements ChunkManager, Metadatable{ } if($spawn instanceof Vector3){ $v = $spawn->floor(); - for(; $v->y > 0; --$v->y){ - $b = $this->getBlock($v); - if($b === null){ - return $spawn; - }elseif($b->isSolid()){ - $v->y++; - break; - } - } - for(; $v->y < 128; ++$v->y){ - if(!$this->getBlock($v->getSide(1))->isSolid()){ - if(!$this->getBlock($v)->isSolid()){ - return new Position($spawn->x, $v->y === Math::floorFloat($spawn->y) ? $spawn->y : $v->y, $spawn->z, $this); + $chunk = $this->getChunk($v->x >> 4, $v->z >> 4, false); + $x = $v->x & 0x0f; + $z = $v->z & 0x0f; + if($chunk !== null){ + for(; $v->y > 0; --$v->y){ + if(Block::$solid[$chunk->getBlockId($x, $v->y & 0x7f, $z)]){ + $v->y++; + break; + } + } + for(; $v->y < 128; ++$v->y){ + if(!Block::$solid[$chunk->getBlockId($x, $v->y + 1, $z)]){ + if(!Block::$solid[$chunk->getBlockId($x, $v->y, $z)]){ + return new Position($spawn->x, $v->y === Math::floorFloat($spawn->y) ? $spawn->y : $v->y, $spawn->z, $this); + } + }else{ + ++$v->y; } - }else{ - ++$v->y; } } diff --git a/src/pocketmine/level/format/anvil/Anvil.php b/src/pocketmine/level/format/anvil/Anvil.php index 9a571deaa..1c92e66ac 100644 --- a/src/pocketmine/level/format/anvil/Anvil.php +++ b/src/pocketmine/level/format/anvil/Anvil.php @@ -76,9 +76,7 @@ class Anvil extends McRegion{ * @return RegionLoader */ protected function getRegion($x, $z){ - $index = $x . ":" . $z; - - return isset($this->regions[$index]) ? $this->regions[$index] : null; + return isset($this->regions[$index = Level::chunkHash($x, $z)]) ? $this->regions[$index] : null; } /** @@ -126,8 +124,7 @@ class Anvil extends McRegion{ } protected function loadRegion($x, $z){ - $index = $x . ":" . $z; - if(isset($this->regions[$index])){ + if(isset($this->regions[$index = Level::chunkHash($x, $z)])){ return true; } diff --git a/src/pocketmine/level/format/mcregion/McRegion.php b/src/pocketmine/level/format/mcregion/McRegion.php index 520a255d6..91f4d3d1c 100644 --- a/src/pocketmine/level/format/mcregion/McRegion.php +++ b/src/pocketmine/level/format/mcregion/McRegion.php @@ -216,9 +216,7 @@ class McRegion extends BaseLevelProvider{ * @return RegionLoader */ protected function getRegion($x, $z){ - $index = $x . ":" . $z; - - return isset($this->regions[$index]) ? $this->regions[$index] : null; + return isset($this->regions[$index = Level::chunkHash($x, $z)]) ? $this->regions[$index] : null; } /** @@ -282,8 +280,7 @@ class McRegion extends BaseLevelProvider{ } protected function loadRegion($x, $z){ - $index = $x . ":" . $z; - if(isset($this->regions[$index])){ + if(isset($this->regions[$index = Level::chunkHash($x, $z)])){ return true; }