Level optimization, added new chunk/block hashes

This commit is contained in:
Shoghi Cervantes 2014-12-09 14:36:16 +01:00
parent ddfc9d9ce1
commit 04ecbd1a76
6 changed files with 76 additions and 54 deletions

View File

@ -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);

View File

@ -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()){

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}