diff --git a/src/API/PlayerAPI.php b/src/API/PlayerAPI.php index 39709f69c..8b600d58d 100644 --- a/src/API/PlayerAPI.php +++ b/src/API/PlayerAPI.php @@ -353,9 +353,7 @@ class PlayerAPI{ return $this->server->clients; } - public function broadcastPacket(array $players, $id, $data = array()){ - $data = new CustomPacketHandler($id, "", $data, true); - $packet = array("raw" => chr($id).$data->raw); + public function broadcastPacket(array $players, RakNetDataPacket $packet){ foreach($players as $p){ $p->dataPacket(false, $packet); } diff --git a/src/Player.php b/src/Player.php index 9520108d8..2473c9ba9 100644 --- a/src/Player.php +++ b/src/Player.php @@ -27,7 +27,8 @@ class Player{ private $resendQueue = array(); private $ackQueue = array(); private $receiveCount = -1; - private $buffer = ""; + private $buffer; + private $bufferLen = 0; private $nextBuffer = 0; private $evid = array(); private $lastMovement = 0; @@ -114,9 +115,11 @@ class Player{ $this->slot = 0; $this->hotbar = array(0, -1, -1, -1, -1, -1, -1, -1, -1); $this->packetStats = array(0,0); + $this->buffer = new RakNetDataPacket(RakNetInfo::DATA_PACKET_0); + $this->buffer->data = array(); $this->server->schedule(2, array($this, "handlePacketQueues"), array(), true); $this->server->schedule(20 * 60, array($this, "clearQueue"), array(), true); - $this->evid[] = $this->server->event("server.close", array($this, "close")); + $this->evid[] = $this->server->event("server.close", array($this, "close")); console("[DEBUG] New Session started with ".$ip.":".$port.". MTU ".$this->MTU.", Client ID ".$this->clientID, true, true, 2); } @@ -1106,14 +1109,15 @@ class Player{ $safeCount = (int) (($this->MTU - 1) / 4); $packetCnt = (int) ($ackCnt / $safeCount + 1); for($p = 0; $p < $packetCnt; ++$p){ - $acks = array(); + $pk = new RakNetPacket(RakNetInfo::ACK); + $pk->packets = array(); for($c = 0; $c < $safeCount; ++$c){ if(($k = array_pop($this->ackQueue)) === null){ break; } - $acks[] = $k; + $pk->packets[] = $k; } - $this->send(0xc0, array($acks)); + $this->send($pk); } $this->ackQueue = array(); } @@ -1154,7 +1158,7 @@ class Player{ $limit = $time - 5; //max lag foreach($this->recoveryQueue as $count => $data){ - if($data["sendtime"] > $limit){ + if($data->sendtime > $limit){ break; } unset($this->recoveryQueue[$count]); @@ -1165,8 +1169,8 @@ class Player{ foreach($this->resendQueue as $count => $data){ unset($this->resendQueue[$count]); $this->packetStats[1]++; - $this->lag[] = microtime(true) - $data["sendtime"]; - $cnt = $this->directDataPacket($data["id"], $data, $data["pid"]); + $this->lag[] = microtime(true) - $data->sendtime; + $cnt = $this->directDataPacket($data); if(isset($this->chunkCount[$count])){ unset($this->chunkCount[$count]); $this->chunkCount[$cnt[0]] = true; @@ -2230,17 +2234,20 @@ class Player{ )); } - public function send($pid, $data = array(), $raw = false){ + public function send(RakNetPacket $packet){ if($this->connected === true){ - $this->bandwidthRaw += $this->server->send($pid, $data, $raw, $this->ip, $this->port); + $packet->ip = $this->ip; + $packet->port = $this->port; + $this->bandwidthRaw += $this->server->send($packet); } } public function sendBuffer(){ - if(strlen($this->buffer) > 0){ - $this->directDataPacket(false, array("raw" => $this->buffer), 0x40); + if(strlen($this->buffer) > 0){ + $this->directDataPacket($this->buffer); } - $this->buffer = ""; + $this->buffer = new RakNetDataPacket(RakNetInfo::DATA_PACKET_0); + $this->buffer->data = array(); $this->nextBuffer = microtime(true) + 0.1; } @@ -2272,22 +2279,20 @@ class Player{ return $cnts; } - public function directDataPacket($id, $data = array(), $pid = 0x00, $recover = true){ + public function directDataPacket(RakNetDataPacket $packet, $reliability = 0, $recover = true){ if($this->connected === false){ return false; } - $data["id"] = $id; - $data["pid"] = $pid; - $data["sendtime"] = microtime(true); - $count = $this->counter[0]++; + $packet->encode(); + $pk = new RakNetPacket(RakNetInfo::DATA_PACKET_0); + $pk->data[] = $packet; + $pk->seqNumber = $this->counter[0]++; + $pk->sendtime = microtime(true); if($recover !== false){ - $this->recoveryQueue[$count] = $data; + $this->recoveryQueue[$pk->seqNumber] = $packet; } - $this->send(0x80, array( - $count, - $pid, - $data, - )); + + $this->send($pk); return array($count); } @@ -2297,24 +2302,21 @@ class Player{ * * @return array|bool */ - public function dataPacket($id, $data = array()){ - $data["id"] = $id; - if($id === false){ - $raw = $data["raw"]; - }else{ - $data = new CustomPacketHandler($id, "", $data, true); - $raw = chr($id).$data->raw; - } - $len = strlen($raw); + public function dataPacket(RakNetDataPacket $packet){ + $packet->encode(); + $len = strlen($packet->buffer) + 1; $MTU = $this->MTU - 24; if($len > $MTU){ - return $this->directBigRawPacket(false, $raw); + return $this->directBigRawPacket($packet); } - if((strlen($this->buffer) + $len) >= $MTU){ + if(($this->bufferLen + $len) >= $MTU){ $this->sendBuffer(); } - $this->buffer .= ($this->buffer === "" ? "":"\x40").Utils::writeShort($len << 3).strrev(Utils::writeTriad($this->counter[3]++)).$raw; + + $packet->messageIndex = $this->counter[3]++; + $this->buffer->data[] .= $packet; + $this->bufferLen += 6 + $len; return array(); } diff --git a/src/PocketMinecraftServer.php b/src/PocketMinecraftServer.php index c6ffda609..a5da58f2e 100644 --- a/src/PocketMinecraftServer.php +++ b/src/PocketMinecraftServer.php @@ -421,7 +421,7 @@ class PocketMinecraftServer{ } $dump .= "\r\n\r\n"; $version = new VersionString(); - $dump .= "PocketMine-MP version: ".$version." #".$version->getNumber()." [Protocol ".CURRENT_PROTOCOL."; API ".CURRENT_API_VERSION."]\r\n"; + $dump .= "PocketMine-MP version: ".$version." #".$version->getNumber()." [Protocol ".ProtocolInfo::CURRENT_PROTOCOL."; API ".CURRENT_API_VERSION."]\r\n"; $dump .= "Git commit: ".GIT_COMMIT."\r\n"; $dump .= "Source SHA1 sum: ".SOURCE_SHA1SUM."\r\n"; $dump .= "uname -a: ".php_uname("a")."\r\n"; @@ -473,29 +473,30 @@ class PocketMinecraftServer{ } public static function clientID($ip, $port){ - //faster than string indexes in PHP - return crc32($ip . $port) ^ crc32($port . $ip . BOOTUP_RANDOM); + //return crc32($ip . $port) ^ crc32($port . $ip . BOOTUP_RANDOM); + return md5($ip . ":" . $port . BOOTUP_RANDOM, true); } - public function packetHandler($packet){ - $data =& $packet["data"]; - $CID = PocketMinecraftServer::clientID($packet["ip"], $packet["port"]); + public function packetHandler(Packet $packet){ + $data =& $packet; + $CID = PocketMinecraftServer::clientID($packet->ip, $packet->port); if(isset($this->clients[$CID])){ - $this->clients[$CID]->handlePacket($packet["pid"], $data); + $this->clients[$CID]->handlePacket($packet); }else{ - if($this->handle("server.noauthpacket", $packet) === false){ + if($this->handle("server.noauthpacket.".$packet->pid(), $packet) === false){ return; } - switch($packet["pid"]){ - case 0x01: - case 0x02: + switch($packet->pid()){ + case RakNetInfo::UNCONNECTED_PING: + case RakNetInfo::UNCONNECTED_PING_OPEN_CONNECTIONS: if($this->invisible === true){ - $this->send(0x1c, array( - $data[0], - $this->serverID, - RAKNET_MAGIC, - $this->serverType, - ), false, $packet["ip"], $packet["port"]); + $pk = new RakNetPacket(RakNetInfo::UNCONNECTED_PONG); + $pk->pingID = $packet->pingID; + $pk->serverID = $this->serverID; + $pk->serverType = $this->serverType; + $pk->ip = $packet->ip; + $pk->port = $packet->port; + $this->send($pk); break; } if(!isset($this->custom["times_".$CID])){ @@ -507,12 +508,13 @@ class PocketMinecraftServer{ } $txt = substr($this->description, $this->custom["times_".$CID], $ln); $txt .= substr($this->description, 0, $ln - strlen($txt)); - $this->send(0x1c, array( - $data[0], - $this->serverID, - RAKNET_MAGIC, - $this->serverType. $this->name . " [".count($this->clients)."/".$this->maxClients."] ".$txt, - ), false, $packet["ip"], $packet["port"]); + $pk = new RakNetPacket(RakNetInfo::UNCONNECTED_PONG); + $pk->pingID = $packet->pingID; + $pk->serverID = $this->serverID; + $pk->serverType = $this->name . " [".count($this->clients)."/".$this->maxClients."] ".$txt; + $pk->ip = $packet->ip; + $pk->port = $packet->port; + $this->send($pk); $this->custom["times_".$CID] = ($this->custom["times_".$CID] + 1) % strlen($this->description); break; case 0x05: @@ -556,8 +558,8 @@ class PocketMinecraftServer{ } } - public function send($pid, $data = array(), $raw = false, $dest = false, $port = false){ - return $this->interface->writePacket($pid, $data, $raw, $dest, $port); + public function send(Packet $packet){ + return $this->interface->writePacket($packet); } public function process(){ diff --git a/src/network/raknet/RakNetDataPacket.php b/src/network/raknet/RakNetDataPacket.php index 707e9326c..1798b3fec 100644 --- a/src/network/raknet/RakNetDataPacket.php +++ b/src/network/raknet/RakNetDataPacket.php @@ -21,7 +21,7 @@ abstract class RakNetDataPacket extends stdClass{ private $offset = 0; - private $buffer = b""; + public $buffer = b""; public $reliability = 0; public $hasSplit = false; diff --git a/src/network/raknet/RakNetInfo.php b/src/network/raknet/RakNetInfo.php index ca28de7c8..485f53973 100644 --- a/src/network/raknet/RakNetInfo.php +++ b/src/network/raknet/RakNetInfo.php @@ -57,35 +57,35 @@ class RakNetInfo{ - public static function isRakNet($pid){ + public static function isValid($pid){ switch((int) $pid){ - case UNCONNECTED_PING: - case UNCONNECTED_PING_OPEN_CONNECTIONS: - case OPEN_CONNECTION_REQUEST_1: - case OPEN_CONNECTION_REPLY_1: - case OPEN_CONNECTION_REQUEST_2: - case OPEN_CONNECTION_REPLY_2: - case INCOMPATIBLE_PROTOCOL_VERSION: - case UNCONNECTED_PONG: - case ADVERTISE_SYSTEM: - case DATA_PACKET_0: - case DATA_PACKET_1: - case DATA_PACKET_2: - case DATA_PACKET_3: - case DATA_PACKET_4: - case DATA_PACKET_5: - case DATA_PACKET_6: - case DATA_PACKET_7: - case DATA_PACKET_8: - case DATA_PACKET_9: - case DATA_PACKET_A: - case DATA_PACKET_B: - case DATA_PACKET_C: - case DATA_PACKET_D: - case DATA_PACKET_E: - case DATA_PACKET_F: - case NACK: - case ACK: + case RakNetInfo::UNCONNECTED_PING: + case RakNetInfo::UNCONNECTED_PING_OPEN_CONNECTIONS: + case RakNetInfo::OPEN_CONNECTION_REQUEST_1: + case RakNetInfo::OPEN_CONNECTION_REPLY_1: + case RakNetInfo::OPEN_CONNECTION_REQUEST_2: + case RakNetInfo::OPEN_CONNECTION_REPLY_2: + case RakNetInfo::INCOMPATIBLE_PROTOCOL_VERSION: + case RakNetInfo::UNCONNECTED_PONG: + case RakNetInfo::ADVERTISE_SYSTEM: + case RakNetInfo::DATA_PACKET_0: + case RakNetInfo::DATA_PACKET_1: + case RakNetInfo::DATA_PACKET_2: + case RakNetInfo::DATA_PACKET_3: + case RakNetInfo::DATA_PACKET_4: + case RakNetInfo::DATA_PACKET_5: + case RakNetInfo::DATA_PACKET_6: + case RakNetInfo::DATA_PACKET_7: + case RakNetInfo::DATA_PACKET_8: + case RakNetInfo::DATA_PACKET_9: + case RakNetInfo::DATA_PACKET_A: + case RakNetInfo::DATA_PACKET_B: + case RakNetInfo::DATA_PACKET_C: + case RakNetInfo::DATA_PACKET_D: + case RakNetInfo::DATA_PACKET_E: + case RakNetInfo::DATA_PACKET_F: + case RakNetInfo::NACK: + case RakNetInfo::ACK: return true; default: return false; diff --git a/src/network/raknet/RakNetParser.php b/src/network/raknet/RakNetParser.php index df05211e4..529e134fd 100644 --- a/src/network/raknet/RakNetParser.php +++ b/src/network/raknet/RakNetParser.php @@ -37,7 +37,7 @@ class RakNetParser{ } public function pid(){ - return (int) $this->pid; + return (int) $this->id; } private function get($len){ @@ -120,6 +120,25 @@ class RakNetParser{ $this->data[] = $this->parseDataPacket(); } break; + case RakNetInfo::NACK: + case RakNetInfo::ACK: + $count = $this->getShort(); + $this->packets = array(); + for($i = 0; $i < $count and !$this->feof(); ++$i){ + if($this->getByte() === 0){ + $start = $this->getLTriad(); + $end = $this->getLTriad(); + if(($end - $start) > 4096){ + $end = $start + 4096; + } + for($c = $start; $c <= $end; ++$c){ + $this->packets[] = $c; + } + }else{ + $this->packets[] = $this->getLTriad(); + } + } + break; default: $this->packet = false; break;