Large improvement in chunk sending

This commit is contained in:
Shoghi Cervantes 2013-06-09 20:37:45 +02:00
parent 31490576d2
commit 4a5783b57b
3 changed files with 60 additions and 29 deletions

View File

@ -77,6 +77,7 @@ class Player{
public $craftingItems = array(); public $craftingItems = array();
public $toCraft = array(); public $toCraft = array();
public $lastCraft = 0; public $lastCraft = 0;
private $chunkCount = array();
public function __get($name){ public function __get($name){
if(isset($this->{$name})){ if(isset($this->{$name})){
@ -155,6 +156,15 @@ class Player{
return false; return false;
} }
foreach($this->chunkCount as $i => $count){
if(isset($this->recoveryQueue[$count])){
$this->server->schedule(1, array($this, "getNextChunk"));
return;
}else{
unset($this->chunkCount[$i]);
}
}
$c = key($this->chunksOrder); $c = key($this->chunksOrder);
$d = @$this->chunksOrder[$c]; $d = @$this->chunksOrder[$c];
if($c === null or $d > $this->server->api->getProperty("view-distance")){ if($c === null or $d > $this->server->api->getProperty("view-distance")){
@ -171,13 +181,26 @@ class Player{
$z = $Z << 4; $z = $Z << 4;
$y = $Y << 4; $y = $Y << 4;
$this->level->useChunk($X, $Z, $this); $this->level->useChunk($X, $Z, $this);
$this->dataPacket(MC_CHUNK_DATA, array( $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;
}
}
$this->chunkCount = $this->dataPacket(MC_CHUNK_DATA, array(
"x" => $X,
"z" => $Z,
"data" => $this->level->getOrderedChunk($X, $Z, $Yndex),
));
/*$this->chunkCount = $this->dataPacket(MC_CHUNK_DATA, array(
"x" => $X, "x" => $X,
"z" => $Z, "z" => $Z,
"data" => $this->level->getOrderedMiniChunk($X, $Z, $Y), "data" => $this->level->getOrderedMiniChunk($X, $Z, $Y),
)); ));*/
$tiles = $this->server->query("SELECT ID FROM tiles WHERE spawnable = 1 AND level = '".$this->level->getName()."' AND x >= ".($x - 1)." AND x < ".($x + 17)." AND z >= ".($z - 1)." AND z < ".($z + 17)." AND y >= ".($y - 1)." AND y < ".($y + 17).";"); $tiles = $this->server->query("SELECT ID FROM tiles WHERE spawnable = 1 AND level = '".$this->level->getName()."' AND x >= ".($x - 1)." AND x < ".($x + 17)." AND z >= ".($z - 1)." AND z < ".($z + 17).";");
if($tiles !== false and $tiles !== true){ if($tiles !== false and $tiles !== true){
while(($tile = $tiles->fetchArray(SQLITE3_ASSOC)) !== false){ while(($tile = $tiles->fetchArray(SQLITE3_ASSOC)) !== false){
$tile = $this->server->api->tile->getByID($tile["ID"]); $tile = $this->server->api->tile->getByID($tile["ID"]);
@ -187,13 +210,6 @@ class Player{
} }
} }
if($repeat === false){
$r = (int) ((PLAYER_CHUNKS_PER_SECOND - 20) / 20);
for($i = 0; $i < $r; ++$i){
$this->getNextChunk(true);
}
}
$this->server->schedule(1, array($this, "getNextChunk")); $this->server->schedule(1, array($this, "getNextChunk"));
} }
@ -239,8 +255,8 @@ class Player{
} }
$reason = $reason == "" ? "server stop":$reason; $reason = $reason == "" ? "server stop":$reason;
$this->eventHandler(new Container("You have been kicked. Reason: ".$reason), "server.chat"); $this->eventHandler(new Container("You have been kicked. Reason: ".$reason), "server.chat");
$this->directDataPacket(MC_DISCONNECT);
$this->sendBuffer(); $this->sendBuffer();
$this->directDataPacket(MC_DISCONNECT);
$this->connected = false; $this->connected = false;
$this->level->freeAllChunks($this); $this->level->freeAllChunks($this);
$this->buffer = null; $this->buffer = null;
@ -791,7 +807,7 @@ class Player{
return false; return false;
} }
if($this->packetStats[1] > 2){ if($this->packetStats[1] > 2){
$this->packetLoss = $this->packetStats[1] / max(1, $this->packetStats[0]); $this->packetLoss = $this->packetStats[1] / max(1, $this->packetStats[0] + $this->packetStats[1]);
}else{ }else{
$this->packetLoss = 0; $this->packetLoss = 0;
} }
@ -802,10 +818,6 @@ class Player{
$this->lagStat = array_sum($this->lag) / max(1, count($this->lag)); $this->lagStat = array_sum($this->lag) / max(1, count($this->lag));
$this->lag = array(); $this->lag = array();
$this->sendBuffer(); $this->sendBuffer();
if($this->packetLoss >= PLAYER_MAX_PACKET_LOSS){
$this->sendChat("Your connection suffers a high packet loss of ".round($this->packetLoss * 100, 2)."%");
$this->close("packet loss");
}
$this->lastMeasure = microtime(true); $this->lastMeasure = microtime(true);
} }
@ -907,8 +919,8 @@ class Player{
$this->resendQueue[$count] =& $this->recoveryQueue[$count]; $this->resendQueue[$count] =& $this->recoveryQueue[$count];
$this->lag[] = microtime(true) - $this->recoveryQueue[$count]["sendtime"]; $this->lag[] = microtime(true) - $this->recoveryQueue[$count]["sendtime"];
unset($this->recoveryQueue[$count]); unset($this->recoveryQueue[$count]);
$this->packetStats[1]++;
} }
++$this->packetStats[1];
} }
break; break;
@ -917,8 +929,9 @@ class Player{
if(isset($this->recoveryQueue[$count])){ if(isset($this->recoveryQueue[$count])){
$this->lag[] = microtime(true) - $this->recoveryQueue[$count]["sendtime"]; $this->lag[] = microtime(true) - $this->recoveryQueue[$count]["sendtime"];
unset($this->recoveryQueue[$count]); unset($this->recoveryQueue[$count]);
unset($this->resendQueue[$count]); unset($this->resendQueue[$count]);
} }
++$this->packetStats[0];
} }
break; break;
@ -1699,17 +1712,18 @@ class Player{
$buffer = str_split(($id === false ? "":chr($id)).$buffer, $size); $buffer = str_split(($id === false ? "":chr($id)).$buffer, $size);
$h = Utils::writeInt(count($buffer)).Utils::writeShort($this->bigCnt); $h = Utils::writeInt(count($buffer)).Utils::writeShort($this->bigCnt);
$this->bigCnt = ($this->bigCnt + 1) % 0x10000; $this->bigCnt = ($this->bigCnt + 1) % 0x10000;
$cnts = array();
foreach($buffer as $i => $buf){ foreach($buffer as $i => $buf){
$data["raw"] = Utils::writeShort(strlen($buf) << 3).strrev(Utils::writeTriad($this->counter[3]++)).$h.Utils::writeInt($i).$buf; $data["raw"] = Utils::writeShort(strlen($buf) << 3).strrev(Utils::writeTriad($this->counter[3]++)).$h.Utils::writeInt($i).$buf;
$count = $this->counter[0]++; $cnts[] = $count = $this->counter[0]++;
$this->recoveryQueue[$count] = $data; $this->recoveryQueue[$count] = $data;
$this->send(0x80, array( $this->send(0x80, array(
$count, $count,
0x50, //0b01010000 0x50, //0b01010000
$data, $data,
)); ));
++$this->packetStats[0];
} }
return $cnts;
} }
public function directDataPacket($id, $data = array(), $pid = 0x00, $recover = true){ public function directDataPacket($id, $data = array(), $pid = 0x00, $recover = true){
@ -1728,7 +1742,7 @@ class Player{
$pid, $pid,
$data, $data,
)); ));
++$this->packetStats[0]; return array($count);
} }
public function dataPacket($id, $data = array()){ public function dataPacket($id, $data = array()){
@ -1742,15 +1756,14 @@ class Player{
$len = strlen($raw); $len = strlen($raw);
$MTU = $this->MTU - 24; $MTU = $this->MTU - 24;
if($len > $MTU){ if($len > $MTU){
$this->directBigRawPacket(false, $raw); return $this->directBigRawPacket(false, $raw);
return;
} }
if((strlen($this->buffer) + $len) >= $MTU){ if((strlen($this->buffer) + $len) >= $MTU){
$this->sendBuffer(); $this->sendBuffer();
} }
$this->buffer .= ($this->buffer === "" ? "":"\x40").Utils::writeShort($len << 3).strrev(Utils::writeTriad($this->counter[3]++)).$raw; $this->buffer .= ($this->buffer === "" ? "":"\x40").Utils::writeShort($len << 3).strrev(Utils::writeTriad($this->counter[3]++)).$raw;
return array();
} }
function __toString(){ function __toString(){

View File

@ -37,10 +37,6 @@ define("VIEWER", 3);
//Players //Players
define("PLAYER_CHUNKS_PER_SECOND", 60);
define("PLAYER_RECOVERY_BUFFER", 1024);
define("PLAYER_MAX_PACKET_LOSS", 0.20);
define("PLAYER_SURVIVAL_SLOTS", 36); define("PLAYER_SURVIVAL_SLOTS", 36);
define("PLAYER_CREATIVE_SLOTS", 111); define("PLAYER_CREATIVE_SLOTS", 111);

View File

@ -375,7 +375,29 @@ class Level{
} }
return $this->level->unloadChunk($X, $Z); return $this->level->unloadChunk($X, $Z);
} }
public function getOrderedChunk($X, $Z, $Yndex){
if(!isset($this->level)){
return false;
}
$raw = array();
for($Y = 0; $Y < 8; ++$Y){
if(($Yndex & (1 << $Y)) > 0){
$raw[$Y] = $this->level->getMiniChunk($X, $Z, $Y);
}
}
$ordered = "";
$flag = chr($Yndex);
for($j = 0; $j < 256; ++$j){
$ordered .= $flag;
foreach($raw as $mini){
$ordered .= substr($mini, $j << 5, 24); //16 + 8
}
}
return $ordered;
}
public function getOrderedMiniChunk($X, $Z, $Y){ public function getOrderedMiniChunk($X, $Z, $Y){
if(!isset($this->level)){ if(!isset($this->level)){
return false; return false;