From 9d02ed9a28899ab1872fa8731209f78c86b86c47 Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Sat, 1 Mar 2014 17:35:44 +0100 Subject: [PATCH] New chunk indexing and sending algorithm --- src/API/PlayerAPI.php | 15 ++++--- src/Entity.php | 18 ++++---- src/MainServer.php | 8 +--- src/Player.php | 61 ++++++++++++++------------- src/network/UDPSocket.php | 4 +- src/world/Level.php | 87 +++++++++++++++++++++++---------------- 6 files changed, 106 insertions(+), 87 deletions(-) diff --git a/src/API/PlayerAPI.php b/src/API/PlayerAPI.php index 42fcf501b..f71d7a2a7 100644 --- a/src/API/PlayerAPI.php +++ b/src/API/PlayerAPI.php @@ -41,13 +41,12 @@ class PlayerAPI{ $this->server->api->ban->cmdWhitelist("list"); $this->server->api->ban->cmdWhitelist("ping"); $this->server->api->ban->cmdWhitelist("spawn"); - $this->server->preparedSQL->selectPlayersToHeal = $this->server->database->prepare("SELECT EID FROM entities WHERE class = ".ENTITY_PLAYER." AND health < 20;"); } public function handle($data, $event){ switch($event){ case "server.regeneration": - if($this->server->difficulty === 0){ + /*if($this->server->difficulty === 0){ $result = $this->server->preparedSQL->selectPlayersToHeal->execute(); if($result !== false){ while(($player = $result->fetchArray()) !== false){ @@ -60,7 +59,7 @@ class PlayerAPI{ } return true; } - } + }*/ break; case "player.death": if(is_numeric($data["cause"])){ @@ -267,7 +266,7 @@ class PlayerAPI{ if(!isset($params[0]) and ($issuer instanceof Player)){ $player = $issuer; }else{ - $player = $this->get($params[0]); + $player = Player::get($params[0]); } if($player instanceof Player){ $player->entity->harm(1000, "console", true); @@ -294,7 +293,7 @@ class PlayerAPI{ if(substr($target, 0, 2) === "w:"){ $lv = $this->server->api->level->get(substr($target, 2)); if($lv instanceof Level){ - $origin = $this->get($name); + $origin = Player::get($name); if($origin instanceof Player){ $name = $origin->username; return $origin->teleport($lv->getSafeSpawn()); @@ -303,10 +302,10 @@ class PlayerAPI{ return false; } } - $player = $this->get($target); + $player = Player::get($target); if(($player instanceof Player) and ($player->entity instanceof Entity)){ $target = $player->username; - $origin = $this->get($name); + $origin = Player::get($name); if($origin instanceof Player){ $name = $origin->username; return $origin->teleport($player->entity); @@ -316,7 +315,7 @@ class PlayerAPI{ } public function tppos(&$name, &$x, &$y, &$z){ - $player = $this->get($name); + $player = Player::get($name); if(($player instanceof Player) and ($player->entity instanceof Entity)){ $name = $player->username; $x = $x{0} === "~" ? $player->entity->x + floatval(substr($x, 1)):floatval($x); diff --git a/src/Entity.php b/src/Entity.php index 219ab43b3..8caf0b38f 100644 --- a/src/Entity.php +++ b/src/Entity.php @@ -25,8 +25,8 @@ abstract class Entity extends Position{ public static $needUpdate = array(); private $id; - //public $passenger = null; - //public $vehicle = null; + public $passenger = null; + public $vehicle = null; public $chunkIndex; @@ -258,12 +258,14 @@ abstract class Entity extends Position{ unset($this->level->chunkEntities[$this->chunkIndex][$this->id]); $this->despawnFromAll(); if($this instanceof Player){ - foreach($this->chunksLoaded as $index => $boolean){ - $X = null; - $Z = null; - PMFLevel::getXZ($index, $X, $Z); - foreach($this->level->getChunkEntities($X, $Z) as $entity){ - $entity->despawnFrom($this); + foreach($this->chunksLoaded as $index => $Yndex){ + if($Yndex !== 0xff){ + $X = null; + $Z = null; + PMFLevel::getXZ($index, $X, $Z); + foreach($this->level->getChunkEntities($X, $Z) as $entity){ + $entity->despawnFrom($this); + } } } $this->level->freeAllChunks($this); diff --git a/src/MainServer.php b/src/MainServer.php index 9ae687375..836bebd22 100644 --- a/src/MainServer.php +++ b/src/MainServer.php @@ -137,8 +137,6 @@ class MainServer{ $this->preparedSQL->selectHandlers = $this->database->prepare("SELECT DISTINCT ID FROM handlers WHERE name = :name ORDER BY priority DESC;"); $this->preparedSQL->selectActions = $this->database->prepare("SELECT ID,code,repeat FROM actions WHERE last <= (:time - interval);"); $this->preparedSQL->updateAction = $this->database->prepare("UPDATE actions SET last = :time WHERE ID = :id;"); - $this->preparedSQL->entity->setPosition = $this->database->prepare("UPDATE entities SET x = :x, y = :y, z = :z, pitch = :pitch, yaw = :yaw WHERE EID = :eid ;"); - $this->preparedSQL->entity->setLevel = $this->database->prepare("UPDATE entities SET level = :level WHERE EID = :eid ;"); } public function query($sql, $fetch = false){ @@ -154,10 +152,8 @@ class MainServer{ $info["tps"] = $this->getTPS(); $info["memory_usage"] = round((memory_get_usage() / 1024) / 1024, 2)."MB"; $info["memory_peak_usage"] = round((memory_get_peak_usage() / 1024) / 1024, 2)."MB"; - $info["entities"] = $this->query("SELECT count(EID) as count FROM entities;", true); - $info["entities"] = $info["entities"]["count"]; - $info["players"] = $this->query("SELECT count(CID) as count FROM players;", true); - $info["players"] = $info["players"]["count"]; + $info["entities"] = count(Entity::$list); + $info["players"] = count(Player::$list); $info["events"] = count($this->eventsID); $info["handlers"] = $this->query("SELECT count(ID) as count FROM handlers;", true); $info["handlers"] = $info["handlers"]["count"]; diff --git a/src/Player.php b/src/Player.php index 9f38c8c62..effea7fa4 100644 --- a/src/Player.php +++ b/src/Player.php @@ -181,7 +181,7 @@ class Player extends PlayerEntity{ } $newOrder = array(); - $lastLoaded = $this->chunksLoaded; + $lastChunk = $this->chunksLoaded; $centerX = intval(($this->x - 0.5) / 16); $centerZ = intval(($this->z - 0.5) / 16); $startX = $centerX - $this->viewDistance; @@ -191,21 +191,26 @@ class Player extends PlayerEntity{ for($X = $startX; $X <= $finalX; ++$X){ for($Z = $startZ; $Z <= $finalZ; ++$Z){ $distance = abs($X - $centerX) + abs($Z - $centerZ); - for($Y = 0; $Y < 8; ++$Y){ - $index = "$X:$Y:$Z"; - if(!isset($lastLoaded[$index])){ - $newOrder[$index] = $distance; - }else{ - unset($lastLoaded[$index]); - } + $index = PMFLevel::getIndex($X, $Z); + if(!isset($this->chunksLoaded[$index]) or $this->chunksLoaded[$index] !== 0){ + $newOrder[$index] = $distance; } + unset($lastChunk[$index]); } } asort($newOrder); $this->chunksOrder = $newOrder; - foreach($lastLoaded as $index => $distance){ - $id = explode(":", $index); - $this->level->freeChunk($id[0], $id[2], $this); + foreach($lastChunk as $index => $Yndex){ + if($Yndex !== 0xff){ + $X = null; + $Z = null; + PMFLevel::getXZ($index, $X, $Z); + foreach($this->level->getChunkEntities($X, $Z) as $entity){ + if($entity !== $this){ + $entity->despawnFrom($this); + } + } + } unset($this->chunksLoaded[$index]); } } @@ -235,6 +240,11 @@ class Player extends PlayerEntity{ } if(is_array($this->lastChunk)){ + foreach($this->level->getChunkEntities($this->lastChunk[0], $this->lastChunk[1]) as $entity){ + if($entity !== $this){ + $entity->spawnTo($this); + } + } foreach($this->level->getChunkTiles($this->lastChunk[0], $this->lastChunk[1]) as $tile){ if($tile instanceof SpawnableTile){ $tile->spawnTo($this); @@ -243,29 +253,24 @@ class Player extends PlayerEntity{ $this->lastChunk = false; } - $c = key($this->chunksOrder); - $d = @$this->chunksOrder[$c]; - if($c === null or $d === null){ + $index = key($this->chunksOrder); + $distance = @$this->chunksOrder[$index]; + if($index === null or $distance === null){ if($this->chunkScheduled === 0){ $this->server->schedule(40, array($this, "getNextChunk")); } return false; } - unset($this->chunksOrder[$c]); - $this->chunksLoaded[$c] = true; - $id = explode(":", $c); - $X = $id[0]; - $Z = $id[2]; - $Y = $id[1]; - $this->level->useChunk($X, $Z, $this); - $Yndex = 1 << $Y; - for($iY = 0; $iY < 8; ++$iY){ - if(isset($this->chunksOrder["$X:$iY:$Z"])){ - unset($this->chunksOrder["$X:$iY:$Z"]); - $this->chunksLoaded["$X:$iY:$Z"] = true; - $Yndex |= 1 << $iY; - } + unset($this->chunksOrder[$index]); + if(!isset($this->chunksLoaded[$index])){ + $this->chunksLoaded[$index] = 0xff; } + $X = null; + $Z = null; + PMFLevel::getXZ($index, $X, $Z); + $this->level->useChunk($X, $Z, $this); + $Yndex = $this->chunksLoaded[$index]; + $this->chunksLoaded[$index] = 0; //Load them all $pk = new ChunkDataPacket; $pk->chunkX = $X; $pk->chunkZ = $Z; diff --git a/src/network/UDPSocket.php b/src/network/UDPSocket.php index 81a305881..f03d5cdbf 100644 --- a/src/network/UDPSocket.php +++ b/src/network/UDPSocket.php @@ -34,8 +34,8 @@ class UDPSocket{ }else{ if(socket_bind($this->sock, $serverip, $port) === true){ socket_set_option($this->sock, SOL_SOCKET, SO_REUSEADDR, 0); - socket_set_option($this->sock, SOL_SOCKET, SO_SNDBUF, 1024 * 1024 * 2); //2MB - socket_set_option($this->sock, SOL_SOCKET, SO_RCVBUF, 1024 * 1024); //1MB + @socket_set_option($this->sock, SOL_SOCKET, SO_SNDBUF, 1024 * 1024 * 2); //2MB + @socket_set_option($this->sock, SOL_SOCKET, SO_RCVBUF, 1024 * 1024); //1MB $this->unblock(); $this->connected = true; }else{ diff --git a/src/world/Level.php b/src/world/Level.php index 20d5daf7b..c46260d26 100644 --- a/src/world/Level.php +++ b/src/world/Level.php @@ -109,28 +109,37 @@ class Level{ $now = microtime(true); if($this->level->isGenerating === 0 and count($this->changedCount) > 0){ - arsort($this->changedCount); - foreach($this->changedCount as $index => $count){ - if($count < 582){//Optimal value, calculated using the relation between minichunks and single packets - break; + foreach($this->changedCount as $index => $mini){ + for($Y = 0; $Y < 8; ++$Y){ + if(($mini & (1 << $Y)) === 0){ + continue; + } + if(count($this->changedBlocks[$index][$Y]) < 582){//Optimal value, calculated using the relation between minichunks and single packets + continue; + }else{ + foreach($this->players as $p){ + if(isset($p->chunksLoaded[$index])){ + $p->chunksLoaded[$index] |= $mini; + } + } + unset($this->changedBlocks[$index][$Y]); + } } - foreach($this->players as $p){ - unset($p->chunksLoaded[$index]); - } - unset($this->changedBlocks[$index]); } $this->changedCount = array(); if(count($this->changedBlocks) > 0){ - foreach($this->changedBlocks as $blocks){ - foreach($blocks as $b){ - $pk = new UpdateBlockPacket; - $pk->x = $b->x; - $pk->y = $b->y; - $pk->z = $b->z; - $pk->block = $b->getID(); - $pk->meta = $b->getMetadata(); - $this->server->api->player->broadcastPacket($this->players, $pk); + foreach($this->changedBlocks as $index => $mini){ + foreach($mini as $blocks){ + foreach($blocks as $b){ + $pk = new UpdateBlockPacket; + $pk->x = $b->x; + $pk->y = $b->y; + $pk->z = $b->z; + $pk->block = $b->getID(); + $pk->meta = $b->getMetadata(); + $this->server->api->player->broadcastPacket($this->players, $pk); + } } } $this->changedBlocks = array(); @@ -251,16 +260,20 @@ class Level{ $pos = new Position($pos->x, $pos->y, $pos->z, $this); } $block->position($pos); - $i = ($pos->x >> 4).":".($pos->y >> 4).":".($pos->z >> 4); + $index = PMFLevel::getIndex($pos->x >> 4, $pos->z >> 4); if(ADVANCED_CACHE == true){ - Cache::remove("world:{$this->name}:".($pos->x >> 4).":".($pos->z >> 4)); + Cache::remove("world:{$this->name}:{$index}"); } - if(!isset($this->changedBlocks[$i])){ - $this->changedBlocks[$i] = array(); - $this->changedCount[$i] = 0; + if(!isset($this->changedBlocks[$index])){ + $this->changedBlocks[$index] = array(); + $this->changedCount[$index] = 0; } - $this->changedBlocks[$i][] = clone $block; - ++$this->changedCount[$i]; + $Y = $pos->y >> 4; + if(!isset($this->changedBlocks[$index][$Y])){ + $this->changedBlocks[$index][$Y] = array(); + $this->changedCount[$index] |= 1 << $Y; + } + $this->changedBlocks[$index][$Y][] = clone $block; } } return $ret; @@ -287,16 +300,20 @@ class Level{ $pk->meta = $block->getMetadata(); $this->server->api->player->broadcastPacket($this->players, $pk); }else{ - $i = ($pos->x >> 4).":".($pos->y >> 4).":".($pos->z >> 4); - if(!isset($this->changedBlocks[$i])){ - $this->changedBlocks[$i] = array(); - $this->changedCount[$i] = 0; - } + $index = PMFLevel::getIndex($pos->x >> 4, $pos->z >> 4); if(ADVANCED_CACHE == true){ - Cache::remove("world:{$this->name}:".($pos->x >> 4).":".($pos->z >> 4)); + Cache::remove("world:{$this->name}:{$index}"); } - $this->changedBlocks[$i][] = clone $block; - ++$this->changedCount[$i]; + if(!isset($this->changedBlocks[$index])){ + $this->changedBlocks[$index] = array(); + $this->changedCount[$index] = 0; + } + $Y = $pos->y >> 4; + if(!isset($this->changedBlocks[$index][$Y])){ + $this->changedBlocks[$index][$Y] = array(); + $this->changedCount[$index] |= 1 << $Y; + } + $this->changedBlocks[$index][$Y][] = clone $block; } if($update === true){ @@ -440,8 +457,8 @@ class Level{ if(!isset($this->level)){ return false; } - if(ADVANCED_CACHE == true and $Yndex == 0xff){ - $identifier = "world:{$this->name}:$X:$Z"; + if(ADVANCED_CACHE == true and $Yndex === 0xff){ + $identifier = "world:{$this->name}:".PMFLevel::getIndex($X, $Z); if(($cache = Cache::get($identifier)) !== false){ return $cache; } @@ -450,7 +467,7 @@ class Level{ $raw = array(); for($Y = 0; $Y < 8; ++$Y){ - if(($Yndex & (1 << $Y)) > 0){ + if(($Yndex & (1 << $Y)) !== 0){ $raw[$Y] = $this->level->getMiniChunk($X, $Z, $Y); } }