diff --git a/.gitmodules b/.gitmodules index 76848a4c1c..ca27060a85 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,8 +1,8 @@ [submodule "src/pocketmine/gui"] path = src/pocketmine/gui - url = git://github.com/PocketMine/PocketMine-MP-GUI.git + url = https://github.com/PocketMine/PocketMine-MP-GUI.git branch = master [submodule "src/raklib"] path = src/raklib - url = git://github.com/PocketMine/RakLib.git + url = https://github.com/PocketMine/RakLib.git branch = master diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 32cf836dad..56b157e81a 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -74,6 +74,7 @@ use pocketmine\network\protocol\UnknownPacket; use pocketmine\network\protocol\UpdateBlockPacket; use pocketmine\network\raknet\Info; use pocketmine\network\raknet\Packet; +use pocketmine\network\SourceInterface; use pocketmine\permission\PermissibleBase; use pocketmine\permission\PermissionAttachment; use pocketmine\plugin\Plugin; @@ -100,8 +101,9 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ const SURVIVAL_SLOTS = 36; const CREATIVE_SLOTS = 112; - public $CID; - public $MTU; + /** @var SourceInterface */ + protected $interface; + public $spawned = false; public $loggedIn = false; public $gamemode; @@ -113,6 +115,8 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ /** @var Inventory[] */ protected $windowIndex = []; + protected $sendIndex = 0; + public $blocked = true; public $achievements = []; public $chunksLoaded = []; @@ -137,32 +141,13 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ protected $chunksOrder = []; /** @var Player[] */ protected $hiddenPlayers = []; - private $recoveryQueue = []; - private $receiveQueue = []; - private $resendQueue = []; - private $ackQueue = []; - private $receiveCount = -1; - /** @var \pocketmine\network\raknet\Packet */ - private $buffer; - private $bufferLen = 0; - private $nextBuffer = 0; - private $timeout; - private $counter = array(0, 0, 0, 0); + private $viewDistance; - private $lastMeasure = 0; - private $bandwidthRaw = 0; - private $bandwidthStats = array(0, 0, 0); - private $lag = []; - private $lagStat = 0; private $spawnPosition; - private $packetLoss = 0; + private $lastChunk = false; private $chunkScheduled = 0; private $inAction = false; - private $bigCnt; - private $packetStats; - private $chunkCount = []; - private $received = []; /** * @var \pocketmine\scheduler\TaskHandler[] @@ -213,7 +198,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ } protected function initEntity(){ - $this->getLevel()->players[$this->CID] = $this; + $this->getLevel()->players[spl_object_hash($this)] = $this; parent::initEntity(); } @@ -363,21 +348,19 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ /** - * @param integer $clientID - * @param string $ip - * @param integer $port - * @param integer $MTU + * @param SourceInterface $interface + * @param integer $clientID + * @param string $ip + * @param integer $port */ - public function __construct($clientID, $ip, $port, $MTU){ + public function __construct(SourceInterface $interface, $clientID, $ip, $port){ + $this->interface = $interface; $this->windows = new \SplObjectStorage(); $this->perm = new PermissibleBase($this); $this->namedtag = new Compound(); - $this->bigCnt = 0; - $this->MTU = $MTU; $this->server = Server::getInstance(); $this->lastBreak = microtime(true); $this->clientID = $clientID; - $this->CID = $ip . ":" . $port; $this->ip = $ip; $this->port = $port; $this->spawnPosition = $this->server->getDefaultLevel()->getSafeSpawn(); @@ -387,13 +370,8 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $this->viewDistance = $this->server->getViewDistance(); $this->slot = 0; $this->hotbar = array(0, -1, -1, -1, -1, -1, -1, -1, -1); - $this->packetStats = array(0, 0); - $this->buffer = new Packet(Info::DATA_PACKET_0); - $this->buffer->data = []; - $this->tasks[] = $this->server->getScheduler()->scheduleRepeatingTask(new CallbackTask(array($this, "handlePacketQueues")), 1); - $this->tasks[] = $this->server->getScheduler()->scheduleRepeatingTask(new CallbackTask(array($this, "clearQueue")), 20 * 60); - $this->server->getLogger()->debug("New Session started with " . $ip . ":" . $port . ". MTU " . $this->MTU . ", Client ID " . $this->clientID); + $this->server->getLogger()->debug("New Session started with " . $ip . ":" . $port . ", Client ID " . $this->clientID); } /** @@ -515,19 +493,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ } } - foreach($this->chunkCount as $count => $t){ - if(isset($this->recoveryQueue[$count]) or isset($this->resendQueue[$count])){ - if($this->chunkScheduled === 0){ - $this->server->getScheduler()->scheduleDelayedTask(new CallbackTask(array($this, "getNextChunk"), array(false, true)), MAX_CHUNK_RATE); - ++$this->chunkScheduled; - } - - return; - }else{ - unset($this->chunkCount[$count]); - } - } - if(is_array($this->lastChunk)){ foreach($this->getLevel()->getChunkEntities($this->lastChunk[0], $this->lastChunk[1]) as $entity){ if($entity !== $this){ @@ -578,10 +543,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ if($cnt === false){ return false; } - $this->chunkCount = []; - foreach($cnt as $count){ - $this->chunkCount[$count] = true; - } $this->lastChunk = array($X, $Z); @@ -669,95 +630,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ return false; } - $packet->encode(); - $len = strlen($packet->buffer) + 1; - $MTU = $this->MTU - 24; - if($len > $MTU){ - return $this->directBigRawPacket($packet); - } - - if(($this->bufferLen + $len) >= $MTU){ - $this->sendBuffer(); - } - - $packet->messageIndex = $this->counter[3]++; - $packet->reliability = 2; - @$this->buffer->data[] = $packet; - $this->bufferLen += 6 + $len; - - return []; - } - - private function directBigRawPacket(DataPacket $packet){ - if($this->connected === false){ - return false; - } - - $sendtime = microtime(true); - - $size = $this->MTU - 34; - $buffer = str_split($packet->buffer, $size); - $bigCnt = $this->bigCnt; - $this->bigCnt = ($this->bigCnt + 1) % 0x10000; - $cnts = []; - $bufCount = count($buffer); - foreach($buffer as $i => $buf){ - $cnts[] = $count = $this->counter[0]++; - - $pk = new UnknownPacket; - $pk->packetID = $packet->pid(); - $pk->reliability = 2; - $pk->hasSplit = true; - $pk->splitCount = $bufCount; - $pk->splitID = $bigCnt; - $pk->splitIndex = $i; - $pk->buffer = $buf; - $pk->messageIndex = $this->counter[3]++; - - $rk = new Packet(Info::DATA_PACKET_0); - $rk->data[] = $pk; - $rk->seqNumber = $count; - $rk->sendtime = $sendtime; - $this->recoveryQueue[$count] = $rk; - $this->send($rk); - } - - return $cnts; - } - - /** - * Sends a raw Packet to the conection - * - * WARNING: Do not use this, it's only for internal use. - * Changes to this function won't be recorded on the version. - * - * @param Packet $packet - */ - public function send(Packet $packet){ - if($this->connected === true){ - $packet->ip = $this->ip; - $packet->port = $this->port; - $this->bandwidthRaw += $this->server->sendPacket($packet); - } - } - - /** - * Forces sending the buffer - * - * WARNING: Do not use this, it's only for internal use. - * Changes to this function won't be recorded on the version. - */ - public function sendBuffer(){ - if($this->connected === true){ - if($this->bufferLen > 0 and $this->buffer instanceof Packet){ - $this->buffer->seqNumber = $this->counter[0]++; - $this->send($this->buffer); - } - $this->bufferLen = 0; - $this->buffer = new Packet(Info::DATA_PACKET_0); - $this->buffer->data = []; - $this->nextBuffer = microtime(true) + 0.1; - } + $this->interface->putPacket($this, $packet); } /** @@ -1032,40 +905,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $this->dataPacket($pk); } - /** - * WARNING: Do not use this, it's only for internal use. - * Changes to this function won't be recorded on the version. - * - * @return bool - */ - public function measureLag(){ - if($this->connected === false){ - return false; - } - if($this->packetStats[1] > 2){ - $this->packetLoss = $this->packetStats[1] / max(1, $this->packetStats[0] + $this->packetStats[1]); - }else{ - $this->packetLoss = 0; - } - $this->packetStats = array(0, 0); - array_shift($this->bandwidthStats); - $this->bandwidthStats[] = $this->bandwidthRaw / max(0.00001, microtime(true) - $this->lastMeasure); - $this->bandwidthRaw = 0; - $this->lagStat = array_sum($this->lag) / max(1, count($this->lag)); - $this->lag = []; - $this->sendBuffer(); - $this->lastMeasure = microtime(true); - } - - /** - * WARNING: Experimental method - * - * @return int - */ - public function getLag(){ - return $this->lagStat * 1000; - } - protected function getCreativeBlock(Item $item){ foreach(Block::$creative as $i => $d){ if($d[0] === $item->getID() and $d[1] === $item->getDamage()){ @@ -1075,139 +914,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ return -1; } - /** - * WARNING: Experimental method - * - * @return int - */ - public function getPacketLoss(){ - return $this->packetLoss; - } - - /** - * WARNING: Experimental method - * - * @return float - */ - public function getBandwidth(){ - return array_sum($this->bandwidthStats) / max(1, count($this->bandwidthStats)); - } - - /** - * WARNING: Do not use this, it's only for internal use. - * Changes to this function won't be recorded on the version. - * - * @return bool - */ - public function clearQueue(){ - if($this->connected === false){ - return false; - } - ksort($this->received); - if(($cnt = count($this->received)) > self::MAX_QUEUE){ - foreach($this->received as $c => $t){ - unset($this->received[$c]); - --$cnt; - if($cnt <= self::MAX_QUEUE){ - break; - } - } - } - } - - /** - * WARNING: Do not use this, it's only for internal use. - * Changes to this function won't be recorded on the version. - * - * @return bool - */ - public function handlePacketQueues(){ - if($this->connected === false){ - return false; - } - $time = microtime(true); - if($time > $this->timeout){ - $this->close($this->username . " has left the game", "timeout"); - - return false; - } - - if(($ackCnt = count($this->ackQueue)) > 0){ - rsort($this->ackQueue); - $safeCount = (int) (($this->MTU - 1) / 4); - $packetCnt = (int) ($ackCnt / $safeCount + 1); - for($p = 0; $p < $packetCnt; ++$p){ - $pk = new Packet(Info::ACK); - $pk->packets = []; - for($c = 0; $c < $safeCount; ++$c){ - if(($k = array_pop($this->ackQueue)) === null){ - break; - } - $pk->packets[] = $k; - } - $this->send($pk); - } - $this->ackQueue = []; - } - - if(($receiveCnt = count($this->receiveQueue)) > 0){ - ksort($this->receiveQueue); - foreach($this->receiveQueue as $count => $packets){ - unset($this->receiveQueue[$count]); - foreach($packets as $p){ - if($p instanceof DataPacket and $p->hasSplit === false){ - if(isset($p->messageIndex) and $p->messageIndex !== false){ - if($p->messageIndex > $this->receiveCount){ - $this->receiveCount = $p->messageIndex; - }elseif($p->messageIndex !== 0){ - if(isset($this->received[$p->messageIndex])){ - continue; - } - switch($p->pid()){ - case 0x01: - case ProtocolInfo::PING_PACKET: - case ProtocolInfo::PONG_PACKET: - case ProtocolInfo::MOVE_PLAYER_PACKET: - case ProtocolInfo::REQUEST_CHUNK_PACKET: - case ProtocolInfo::ANIMATE_PACKET: - case ProtocolInfo::SET_HEALTH_PACKET: - continue; - } - } - $this->received[$p->messageIndex] = true; - } - $p->decode(); - $this->handleDataPacket($p); - } - } - } - } - - if($this->nextBuffer <= $time and $this->bufferLen > 0){ - $this->sendBuffer(); - } - - $limit = $time - 5; //max lag - foreach($this->recoveryQueue as $count => $data){ - if($data->sendtime > $limit){ - break; - } - unset($this->recoveryQueue[$count]); - $this->resendQueue[$count] = $data; - } - - if(($resendCnt = count($this->resendQueue)) > 0){ - foreach($this->resendQueue as $count => $data){ - unset($this->resendQueue[$count]); - $this->packetStats[1]++; - $this->lag[] = microtime(true) - $data->sendtime; - $data->sendtime = microtime(true); - $this->send($data); - $this->recoveryQueue[$count] = $data; - } - } - } - public function onUpdate(){ if($this->spawned === false){ return true; @@ -1267,6 +973,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ if($this->connected === false){ return; } + $packet->decode(); $this->server->getPluginManager()->callEvent($ev = new DataPacketReceiveEvent($this, $packet)); if($ev->isCancelled()){ @@ -1274,34 +981,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ } switch($packet->pid()){ - case 0x01: - break; - case ProtocolInfo::PONG_PACKET: - break; - case ProtocolInfo::PING_PACKET: - $pk = new PongPacket; - $pk->ptime = $packet->time; - $pk->time = abs(microtime(true) * 1000); - $this->directDataPacket($pk); - break; - case ProtocolInfo::DISCONNECT_PACKET: - $this->close($this->username . " has left the game", "client disconnect"); - break; - case ProtocolInfo::CLIENT_CONNECT_PACKET: - if($this->loggedIn === true){ - break; - } - $pk = new ServerHandshakePacket; - $pk->port = $this->port; - $pk->session = $packet->session; - $pk->session2 = Binary::readLong("\x00\x00\x00\x00\x04\x44\x0b\xa9"); - $this->dataPacket($pk); - break; - case ProtocolInfo::CLIENT_HANDSHAKE_PACKET: - if($this->loggedIn === true){ - break; - } - break; case ProtocolInfo::LOGIN_PACKET: if($this->loggedIn === true){ break; @@ -1321,11 +1000,11 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ if($packet->protocol1 < ProtocolInfo::CURRENT_PROTOCOL){ $pk = new LoginStatusPacket; $pk->status = 1; - $this->directDataPacket($pk); + $this->dataPacket($pk); }else{ $pk = new LoginStatusPacket; $pk->status = 2; - $this->directDataPacket($pk); + $this->dataPacket($pk); } $this->close("", "Incorrect protocol #" . $packet->protocol1, false); @@ -1454,7 +1133,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ //$this->evid[] = $this->server->event("tile.container.slot", array($this, "eventHandler")); //$this->evid[] = $this->server->event("tile.update", array($this, "eventHandler")); $this->lastMeasure = microtime(true); - $this->tasks[] = $this->server->getScheduler()->scheduleRepeatingTask(new CallbackTask(array($this, "measureLag")), 50); $this->server->getLogger()->info(TextFormat::AQUA . $this->username . TextFormat::WHITE . "[/" . $this->ip . ":" . $this->port . "] logged in with entity id " . $this->id . " at (" . $this->getLevel()->getName() . ", " . round($this->x, 4) . ", " . round($this->y, 4) . ", " . round($this->z, 4) . ")"); @@ -1492,7 +1170,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $this->teleport($ev->getRespawnPosition()); $this->spawnToAll(); - $this->sendBuffer(); break; case 2: //Chunk loaded? @@ -1509,28 +1186,27 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ if($this->spawned === false){ break; } - if($packet->messageIndex > $this->lastMovement){ - $this->lastMovement = $packet->messageIndex; - $newPos = new Vector3($packet->x, $packet->y, $packet->z); - if($this->forceMovement instanceof Vector3){ - if($this->forceMovement->distance($newPos) <= 0.7){ - $this->forceMovement = false; - }else{ - $this->setPosition($this->forceMovement); - } + + $newPos = new Vector3($packet->x, $packet->y, $packet->z); + if($this->forceMovement instanceof Vector3){ + if($this->forceMovement->distance($newPos) <= 0.7){ + $this->forceMovement = false; + }else{ + $this->setPosition($this->forceMovement); } - /*$speed = $this->entity->getSpeedMeasure(); - if($this->blocked === true or ($this->server->api->getProperty("allow-flight") !== true and (($speed > 9 and ($this->gamemode & 0x01) === 0x00) or $speed > 20 or $this->entity->distance($newPos) > 7)) or $this->server->api->handle("player.move", $this->entity) === false){ - if($this->lastCorrect instanceof Vector3){ - $this->teleport($this->lastCorrect, $this->entity->yaw, $this->entity->pitch, false); - } - if($this->blocked !== true){ - $this->server->getLogger()->warning($this->username." moved too quickly!"); - } - }else{*/ - $this->setPositionAndRotation($newPos, $packet->yaw, $packet->pitch); - //} } + /*$speed = $this->entity->getSpeedMeasure(); + if($this->blocked === true or ($this->server->api->getProperty("allow-flight") !== true and (($speed > 9 and ($this->gamemode & 0x01) === 0x00) or $speed > 20 or $this->entity->distance($newPos) > 7)) or $this->server->api->handle("player.move", $this->entity) === false){ + if($this->lastCorrect instanceof Vector3){ + $this->teleport($this->lastCorrect, $this->entity->yaw, $this->entity->pitch, false); + } + if($this->blocked !== true){ + $this->server->getLogger()->warning($this->username." moved too quickly!"); + } + }else{*/ + $this->setPositionAndRotation($newPos, $packet->yaw, $packet->pitch); + //} + break; case ProtocolInfo::PLAYER_EQUIPMENT_PACKET: if($this->spawned === false){ @@ -1754,7 +1430,8 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $pk->z = $target->z; $pk->block = $target->getID(); $pk->meta = $target->getDamage(); - $this->directDataPacket($pk); + $this->dataPacket($pk); + //TODO: priority if($tile instanceof Spawnable){ $tile->spawnTo($this); } @@ -2228,7 +1905,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ */ public function close($message = "", $reason = "generic reason"){ if($this->connected === true){ - unset($this->getLevel()->players[$this->CID]); + unset($this->getLevel()->players[spl_object_hash($this)]); if($this->username != ""){ $this->server->getPluginManager()->callEvent($ev = new PlayerQuitEvent($this, $message)); if($this->loggedIn === true){ @@ -2237,8 +1914,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ } } - $this->sendBuffer(); - $this->directDataPacket(new DisconnectPacket); + $this->interface->close($this, $reason); $this->connected = false; $this->server->removePlayer($this); $this->getLevel()->freeAllChunks($this); @@ -2247,10 +1923,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $task->cancel(); } $this->tasks = []; - $this->recoveryQueue = []; - $this->receiveQueue = []; - $this->resendQueue = []; - $this->ackQueue = []; if(isset($ev) and $this->username != "" and $this->spawned !== false and $ev->getQuitMessage() != ""){ $this->server->broadcastMessage($ev->getQuitMessage()); @@ -2262,9 +1934,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $this->windowIndex = []; $this->chunksLoaded = []; $this->chunksOrder = []; - $this->chunkCount = []; - $this->received = []; - $this->buffer = null; unset($this->buffer); } } @@ -2294,37 +1963,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ } } - /** - * Sends a Minecraft packet directly, bypassing the send buffers - * - * @param DataPacket $packet - * @param bool $recover - * - * @return array|bool - */ - public function directDataPacket(DataPacket $packet, $recover = true){ - if($this->connected === false){ - return false; - } - - $this->server->getPluginManager()->callEvent($ev = new DataPacketSendEvent($this, $packet)); - if($ev->isCancelled()){ - return []; - } - $packet->encode(); - $pk = new Packet(Info::DATA_PACKET_0); - $pk->data[] = $packet; - $pk->seqNumber = $this->counter[0]++; - $pk->sendtime = microtime(true); - if($recover !== false){ - $this->recoveryQueue[$pk->seqNumber] = $pk; - } - - $this->send($pk); - - return array($pk->seqNumber); - } - /** * Gets the username * @@ -2402,63 +2040,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $this->server->getPlayerMetadata()->removeMetadata($this, $metadataKey, $plugin); } - /** - * Handles a RakNet Packet - * - * @param Packet $packet - */ - public function handlePacket(Packet $packet){ - if($this->connected === true){ - $this->timeout = microtime(true) + 20; - switch($packet->pid()){ - case Info::NACK: - foreach($packet->packets as $count){ - if(isset($this->recoveryQueue[$count])){ - $this->resendQueue[$count] =& $this->recoveryQueue[$count]; - $this->lag[] = microtime(true) - $this->recoveryQueue[$count]->sendtime; - unset($this->recoveryQueue[$count]); - } - ++$this->packetStats[1]; - } - break; - - case Info::ACK: - foreach($packet->packets as $count){ - if(isset($this->recoveryQueue[$count])){ - $this->lag[] = microtime(true) - $this->recoveryQueue[$count]->sendtime; - unset($this->recoveryQueue[$count]); - unset($this->resendQueue[$count]); - } - ++$this->packetStats[0]; - } - break; - - case Info::DATA_PACKET_0: - case Info::DATA_PACKET_1: - case Info::DATA_PACKET_2: - case Info::DATA_PACKET_3: - case Info::DATA_PACKET_4: - case Info::DATA_PACKET_5: - case Info::DATA_PACKET_6: - case Info::DATA_PACKET_7: - case Info::DATA_PACKET_8: - case Info::DATA_PACKET_9: - case Info::DATA_PACKET_A: - case Info::DATA_PACKET_B: - case Info::DATA_PACKET_C: - case Info::DATA_PACKET_D: - case Info::DATA_PACKET_E: - case Info::DATA_PACKET_F: - $this->ackQueue[] = $packet->seqNumber; - $this->receiveQueue[$packet->seqNumber] = []; - foreach($packet->data as $pk){ - $this->receiveQueue[$packet->seqNumber][] = $pk; - } - break; - } - } - } - } diff --git a/src/pocketmine/PocketMine.php b/src/pocketmine/PocketMine.php index 2972c856a7..e0c3080e02 100644 --- a/src/pocketmine/PocketMine.php +++ b/src/pocketmine/PocketMine.php @@ -70,6 +70,7 @@ namespace pocketmine { use pocketmine\utils\MainLogger; use pocketmine\utils\Utils; use pocketmine\wizard\Installer; + use raklib\RakLib; const VERSION = "Alpha_1.4dev"; const API_VERSION = "1.0.0"; @@ -101,7 +102,12 @@ namespace pocketmine { $autoloader->add("pocketmine", array( \pocketmine\PATH . "src" )); + $autoloader->register(true); + if(!class_exists("raklib\\RakLib", false)){ + require(\pocketmine\PATH . "src/raklib/raklib/RakLib.php"); + } + RakLib::bootstrap($autoloader); //Startup code. Do not look at it, it can harm you. Most of them are hacks to fix date-related bugs, or basic functions used after this diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index b632e8564b..6bb34d6dee 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -35,8 +35,6 @@ use pocketmine\command\PluginIdentifiableCommand; use pocketmine\command\SimpleCommandMap; use pocketmine\entity\Entity; use pocketmine\event\HandlerList; -use pocketmine\event\server\PacketReceiveEvent; -use pocketmine\event\server\PacketSendEvent; use pocketmine\event\server\ServerCommandEvent; use pocketmine\inventory\CraftingManager; use pocketmine\inventory\InventoryType; @@ -62,14 +60,11 @@ use pocketmine\nbt\tag\Int; use pocketmine\nbt\tag\Long; use pocketmine\nbt\tag\Short; use pocketmine\nbt\tag\String; -use pocketmine\network\Packet; use pocketmine\network\protocol\DataPacket; use pocketmine\network\query\QueryHandler; use pocketmine\network\query\QueryPacket; -use pocketmine\network\raknet\Info as RakNetInfo; -use pocketmine\network\raknet\Packet as RakNetPacket; +use pocketmine\network\RakLibInterface; use pocketmine\network\rcon\RCON; -use pocketmine\network\ThreadedHandler; use pocketmine\network\upnp\UPnP; use pocketmine\permission\BanList; use pocketmine\permission\DefaultPermissions; @@ -88,6 +83,7 @@ use pocketmine\utils\MainLogger; use pocketmine\utils\TextFormat; use pocketmine\utils\Utils; use pocketmine\utils\VersionString; +use pocketmine\network\SourceInterface; /** * The class that manages everything @@ -161,8 +157,8 @@ class Server{ private $tickCounter; private $inTick = false; - /** @var ThreadedHandler */ - private $interface; + /** @var SourceInterface[] */ + private $interfaces = []; private $serverID; @@ -449,7 +445,7 @@ class Server{ } /** - * @return Logger + * @return \ThreadedLogger */ public function getLogger(){ return $this->logger; @@ -514,10 +510,17 @@ class Server{ } /** - * @return ThreadedHandler + * @return SourceInterface[] */ - public function getNetwork(){ - return $this->interface; + public function getInterfaces(){ + return $this->interfaces; + } + + /** + * @param SourceInterface $interface + */ + public function addInterface(SourceInterface $interface){ + $this->interfaces[] = $interface; } /** @@ -829,7 +832,7 @@ class Server{ $this->logger->info("Preparing level \"" . $name . "\""); $level = new LevelFormat($path . "level.pmf"); if(!$level->isLoaded){ - console("[ERROR] Could not load level \"" . $name . "\""); + $this->logger->error("Could not load level \"" . $name . "\""); return false; } @@ -1186,12 +1189,12 @@ class Server{ /** * @param \SplClassLoader $autoloader - * @param \Logger $logger + * @param \ThreadedLogger $logger * @param string $filePath * @param string $dataPath * @param string $pluginPath */ - public function __construct(\SplClassLoader $autoloader, \Logger $logger, $filePath, $dataPath, $pluginPath){ + public function __construct(\SplClassLoader $autoloader, \ThreadedLogger $logger, $filePath, $dataPath, $pluginPath){ self::$instance = $this; $this->autoloader = $autoloader; @@ -1279,7 +1282,7 @@ class Server{ $this->logger->setLogDebug(\pocketmine\DEBUG > 1); } define("ADVANCED_CACHE", $this->getConfigBoolean("enable-advanced-cache", false)); - define("MAX_CHUNK_RATE", 20 / $this->getConfigInt("max-chunks-per-second", 7)); //Default rate ~448 kB/s + define("MAX_CHUNK_RATE", 20 / $this->getConfigInt("max-chunks-per-second", 3)); //Default rate ~144 kB/s, TODO: increment this, add backwards notification of packets if(ADVANCED_CACHE == true){ $this->logger->info("Advanced cache enabled"); } @@ -1291,7 +1294,8 @@ class Server{ $this->logger->info("Starting Minecraft PE server on " . ($this->getIp() === "" ? "*" : $this->getIp()) . ":" . $this->getPort()); define("BOOTUP_RANDOM", Utils::getRandomBytes(16)); $this->serverID = Binary::readLong(substr(Utils::getUniqueID(true, $this->getIp() . $this->getPort()), 0, 8)); - $this->interface = new ThreadedHandler("255.255.255.255", $this->getPort(), $this->getIp() === "" ? "0.0.0.0" : $this->getIp()); + + $this->interfaces[] = new RakLibInterface($this); $this->logger->info("This server is running PocketMine-MP version " . ($version->isDev() ? TextFormat::YELLOW : "") . $this->getPocketMineVersion() . TextFormat::RESET . " \"" . $this->getCodename() . "\" (API " . $this->getApiVersion() . ")", true, true, 0); $this->logger->info("PocketMine-MP is distributed under the LGPL License", true, true, 0); @@ -1575,7 +1579,8 @@ class Server{ public function start(){ if($this->getConfigBoolean("enable-query", true) === true){ - $this->queryHandler = new QueryHandler(); + //$this->queryHandler = new QueryHandler(); + //TODO: query } @@ -1614,13 +1619,12 @@ class Server{ private function tickProcessorWindows(){ $lastLoop = 0; while($this->isRunning){ - if(($packet = $this->interface->readPacket()) instanceof Packet){ - $this->pluginManager->callEvent($ev = new PacketReceiveEvent($packet)); - if(!$ev->isCancelled()){ - $this->handlePacket($packet); + foreach($this->interfaces as $interface){ + if($interface->process()){ + $lastLoop = 0; } - $lastLoop = 0; } + if(($ticks = $this->tick()) !== true){ ++$lastLoop; if($lastLoop > 128){ @@ -1729,20 +1733,20 @@ class Server{ ob_end_clean(); $dump .= "\r\n```"; $name = "Error_Dump_" . date("D_M_j-H.i.s-T_Y"); - log($dump, $name, true, 0, true); + //log($dump, $name, true, 0, true); $this->logger->emergency("Please submit the \"{$name}.log\" file to the Bug Reporting page. Give as much info as you can.", true, true, 0); } private function tickProcessor(){ $lastLoop = 0; while($this->isRunning){ - if(($packet = $this->interface->readPacket()) instanceof Packet){ - $this->pluginManager->callEvent($ev = new PacketReceiveEvent($packet)); - if(!$ev->isCancelled()){ - $this->handlePacket($packet); + + foreach($this->interfaces as $interface){ + if($interface->process()){ + $lastLoop = 0; } - $lastLoop = 0; } + if(($ticks = $this->tick()) !== true){ ++$lastLoop; if($lastLoop > 16 and $lastLoop < 128){ @@ -1761,68 +1765,11 @@ class Server{ public function handlePacket(Packet $packet){ if($packet instanceof QueryPacket and isset($this->queryHandler)){ $this->queryHandler->handle($packet); - }elseif($packet instanceof RakNetPacket){ - $CID = $packet->ip . ":" . $packet->port; - if(isset($this->players[$CID])){ - $this->players[$CID]->handlePacket($packet); - }else{ - switch($packet->pid()){ - case RakNetInfo::UNCONNECTED_PING: - case RakNetInfo::UNCONNECTED_PING_OPEN_CONNECTIONS: - $pk = new RakNetPacket(RakNetInfo::UNCONNECTED_PONG); - $pk->pingID = $packet->pingID; - $pk->serverID = $this->serverID; - $pk->serverType = "MCCPP;Demo;" . $this->getMotd() . " [" . count($this->players) . "/" . $this->getMaxPlayers() . "]"; - $pk->ip = $packet->ip; - $pk->port = $packet->port; - $this->sendPacket($pk); - break; - case RakNetInfo::OPEN_CONNECTION_REQUEST_1: - if($packet->structure !== RakNetInfo::STRUCTURE){ - $this->logger->debug("Incorrect structure #" . $packet->structure . " from " . $packet->ip . ":" . $packet->port); - $pk = new RakNetPacket(RakNetInfo::INCOMPATIBLE_PROTOCOL_VERSION); - $pk->serverID = $this->serverID; - $pk->ip = $packet->ip; - $pk->port = $packet->port; - $this->sendPacket($pk); - }else{ - $pk = new RakNetPacket(RakNetInfo::OPEN_CONNECTION_REPLY_1); - $pk->serverID = $this->serverID; - $pk->mtuSize = strlen($packet->buffer); - $pk->ip = $packet->ip; - $pk->port = $packet->port; - $this->sendPacket($pk); - } - break; - case RakNetInfo::OPEN_CONNECTION_REQUEST_2: - $this->players[$CID] = new Player($packet->clientID, $packet->ip, $packet->port, $packet->mtuSize); //New Session! - $pk = new RakNetPacket(RakNetInfo::OPEN_CONNECTION_REPLY_2); - $pk->serverID = $this->serverID; - $pk->serverPort = $this->getPort(); - $pk->mtuSize = $packet->mtuSize; - $pk->ip = $packet->ip; - $pk->port = $packet->port; - $this->sendPacket($pk); - break; - } - } } } - /** - * Sends a packet to the processing queue. Returns the number of bytes - * - * @param Packet $packet - * - * @return int - */ - public function sendPacket(Packet $packet){ - $this->pluginManager->callEvent($ev = new PacketSendEvent($packet)); - if(!$ev->isCancelled()){ - return $this->interface->writePacket($packet); - } - - return 0; + public function addPlayer($identifier, Player $player){ + $this->players[$identifier] = $player; } private function checkTickUpdates($currentTick){ @@ -1895,7 +1842,7 @@ class Server{ public function titleTick(){ if(defined("pocketmine\\DEBUG") and \pocketmine\DEBUG >= 0 and \pocketmine\ANSI === true){ - echo "\x1b]0;PocketMine-MP " . $this->getPocketMineVersion() . " | Online " . count($this->players) . "/" . $this->getMaxPlayers() . " | RAM " . round((memory_get_usage() / 1024) / 1024, 2) . "/" . round((memory_get_usage(true) / 1024) / 1024, 2) . " MB | U " . round($this->interface->getUploadSpeed() / 1024, 2) . " D " . round($this->interface->getDownloadSpeed() / 1024, 2) . " kB/s | TPS " . $this->getTicksPerSecond() . "\x07"; + echo "\x1b]0;PocketMine-MP " . $this->getPocketMineVersion() . " | Online " . count($this->players) . "/" . $this->getMaxPlayers() . " | RAM " . round((memory_get_usage() / 1024) / 1024, 2) . "/" . round((memory_get_usage(true) / 1024) / 1024, 2) . " MB | U -1 D -1 kB/s | TPS " . $this->getTicksPerSecond() . "\x07"; } } diff --git a/src/pocketmine/constants/GeneralConstants.php b/src/pocketmine/constants/GeneralConstants.php deleted file mode 100644 index 6f1544bf9b..0000000000 --- a/src/pocketmine/constants/GeneralConstants.php +++ /dev/null @@ -1,47 +0,0 @@ -packet = $packet; - } - - public function getPacket(){ - return $this->packet; - } -} \ No newline at end of file diff --git a/src/pocketmine/event/server/PacketSendEvent.php b/src/pocketmine/event/server/PacketSendEvent.php deleted file mode 100644 index ec3f880839..0000000000 --- a/src/pocketmine/event/server/PacketSendEvent.php +++ /dev/null @@ -1,41 +0,0 @@ -packet = $packet; - } - - public function getPacket(){ - return $this->packet; - } -} \ No newline at end of file diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 6e6afcabf8..c0087b3c4f 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -2,11 +2,11 @@ /* * - * ____ _ _ __ __ _ __ __ ____ - * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ + * ____ _ _ __ __ _ __ __ ____ + * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) | - * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ - * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| + * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ + * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -15,7 +15,7 @@ * * @author PocketMine Team * @link http://www.pocketmine.net/ - * + * * */ @@ -204,7 +204,7 @@ class Level{ public function useChunk($X, $Z, Player $player){ $index = LevelFormat::getIndex($X, $Z); $this->loadChunk($X, $Z); - $this->usedChunks[$index][$player->CID] = $player; + $this->usedChunks[$index][spl_object_hash($player)] = $player; } /** @@ -215,7 +215,7 @@ class Level{ */ public function freeAllChunks(Player $player){ foreach($this->usedChunks as $i => $c){ - unset($this->usedChunks[$i][$player->CID]); + unset($this->usedChunks[$i][spl_object_hash($player)]); } } @@ -228,7 +228,7 @@ class Level{ * @param Player $player */ public function freeChunk($X, $Z, Player $player){ - unset($this->usedChunks[LevelFormat::getIndex($X, $Z)][$player->CID]); + unset($this->usedChunks[LevelFormat::getIndex($X, $Z)][spl_object_hash($player)]); } /** diff --git a/src/pocketmine/network/Packet.php b/src/pocketmine/network/Packet.php deleted file mode 100644 index 3f7a3d3d46..0000000000 --- a/src/pocketmine/network/Packet.php +++ /dev/null @@ -1,30 +0,0 @@ -server = $server; + $this->identifers = new \SplObjectStorage(); + + $server = new RakLibServer($this->server->getLogger(), $this->server->getLoader(), $this->server->getPort(), $this->server->getIp() === "" ? "0.0.0.0" : $this->server->getIp()); + $this->interface = new ServerHandler($server, $this); + + } + + public function process(){ + $this->interface->handlePacket(); + } + + public function closeSession($identifier, $reason){ + if(isset($this->players[$identifier])){ + $player = $this->players[$identifier]; + $this->identifers->detach($player); + unset($this->players[$identifier]); + $player->close($player->getName() . " has left the game", $reason); + } + } + + public function close(Player $player, $reason = "unknown reason"){ + if(isset($this->identifers[$player])){ + unset($this->players[$this->identifers[$player]]); + $this->interface->closeSession($this->identifers[$player], $reason); + $this->identifers->detach($player); + } + } + + public function shutdown(){ + $this->interface->shutdown(); + } + + public function emergencyShutdown(){ + $this->interface->emergencyShutdown(); + } + + public function openSession($identifier, $address, $port, $clientID){ + $player = new Player($this, $clientID, $address, $port); + $this->players[$identifier] = $player; + $this->identifers->attach($player, $identifier); + $this->server->addPlayer($identifier, $player); + } + + public function handleEncapsulated($identifier, EncapsulatedPacket $packet){ + if(isset($this->players[$identifier])){ + $this->players[$identifier]->handleDataPacket($this->getPacket($packet->buffer)); + } + } + + public function putPacket(Player $player, DataPacket $packet){ + if(isset($this->identifers[$player])){ + $packet->encode(); + $pk = new EncapsulatedPacket(); + $pk->buffer = $packet->buffer; + $pk->reliability = 2; + $this->interface->sendEncapsulated($this->identifers[$player], $pk); + } + } + + private function getPacket($buffer){ + $pid = ord($buffer{0}); + switch($pid){ //TODO: more efficient selection based on range + case ProtocolInfo::LOGIN_PACKET: + $data = new LoginPacket(); + break; + case ProtocolInfo::LOGIN_STATUS_PACKET: + $data = new LoginStatusPacket(); + break; + case ProtocolInfo::READY_PACKET: + $data = new ReadyPacket(); + break; + case ProtocolInfo::MESSAGE_PACKET: + $data = new MessagePacket(); + break; + case ProtocolInfo::SET_TIME_PACKET: + $data = new SetTimePacket(); + break; + case ProtocolInfo::START_GAME_PACKET: + $data = new StartGamePacket(); + break; + case ProtocolInfo::ADD_MOB_PACKET: + $data = new AddMobPacket(); + break; + case ProtocolInfo::ADD_PLAYER_PACKET: + $data = new AddPlayerPacket(); + break; + case ProtocolInfo::REMOVE_PLAYER_PACKET: + $data = new RemovePlayerPacket(); + break; + case ProtocolInfo::ADD_ENTITY_PACKET: + $data = new AddEntityPacket(); + break; + case ProtocolInfo::REMOVE_ENTITY_PACKET: + $data = new RemoveEntityPacket(); + break; + case ProtocolInfo::ADD_ITEM_ENTITY_PACKET: + $data = new AddItemEntityPacket(); + break; + case ProtocolInfo::TAKE_ITEM_ENTITY_PACKET: + $data = new TakeItemEntityPacket(); + break; + case ProtocolInfo::MOVE_ENTITY_PACKET: + $data = new MoveEntityPacket(); + break; + case ProtocolInfo::MOVE_ENTITY_PACKET_POSROT: + $data = new MoveEntityPacket_PosRot(); + break; + case ProtocolInfo::ROTATE_HEAD_PACKET: + $data = new RotateHeadPacket(); + break; + case ProtocolInfo::MOVE_PLAYER_PACKET: + $data = new MovePlayerPacket(); + break; + case ProtocolInfo::REMOVE_BLOCK_PACKET: + $data = new RemoveBlockPacket(); + break; + case ProtocolInfo::UPDATE_BLOCK_PACKET: + $data = new UpdateBlockPacket(); + break; + case ProtocolInfo::ADD_PAINTING_PACKET: + $data = new AddPaintingPacket(); + break; + case ProtocolInfo::EXPLODE_PACKET: + $data = new ExplodePacket(); + break; + case ProtocolInfo::LEVEL_EVENT_PACKET: + $data = new LevelEventPacket(); + break; + case ProtocolInfo::TILE_EVENT_PACKET: + $data = new TileEventPacket(); + break; + case ProtocolInfo::ENTITY_EVENT_PACKET: + $data = new EntityEventPacket(); + break; + case ProtocolInfo::REQUEST_CHUNK_PACKET: + $data = new RequestChunkPacket(); + break; + case ProtocolInfo::CHUNK_DATA_PACKET: + $data = new ChunkDataPacket(); + break; + case ProtocolInfo::PLAYER_EQUIPMENT_PACKET: + $data = new PlayerEquipmentPacket(); + break; + case ProtocolInfo::PLAYER_ARMOR_EQUIPMENT_PACKET: + $data = new PlayerArmorEquipmentPacket(); + break; + case ProtocolInfo::INTERACT_PACKET: + $data = new InteractPacket(); + break; + case ProtocolInfo::USE_ITEM_PACKET: + $data = new UseItemPacket(); + break; + case ProtocolInfo::PLAYER_ACTION_PACKET: + $data = new PlayerActionPacket(); + break; + case ProtocolInfo::HURT_ARMOR_PACKET: + $data = new HurtArmorPacket(); + break; + case ProtocolInfo::SET_ENTITY_DATA_PACKET: + $data = new SetEntityDataPacket(); + break; + case ProtocolInfo::SET_ENTITY_MOTION_PACKET: + $data = new SetEntityMotionPacket(); + break; + case ProtocolInfo::SET_HEALTH_PACKET: + $data = new SetHealthPacket(); + break; + case ProtocolInfo::SET_SPAWN_POSITION_PACKET: + $data = new SetSpawnPositionPacket(); + break; + case ProtocolInfo::ANIMATE_PACKET: + $data = new AnimatePacket(); + break; + case ProtocolInfo::RESPAWN_PACKET: + $data = new RespawnPacket(); + break; + case ProtocolInfo::SEND_INVENTORY_PACKET: + $data = new SendInventoryPacket(); + break; + case ProtocolInfo::DROP_ITEM_PACKET: + $data = new DropItemPacket(); + break; + case ProtocolInfo::CONTAINER_OPEN_PACKET: + $data = new ContainerOpenPacket(); + break; + case ProtocolInfo::CONTAINER_CLOSE_PACKET: + $data = new ContainerClosePacket(); + break; + case ProtocolInfo::CONTAINER_SET_SLOT_PACKET: + $data = new ContainerSetSlotPacket(); + break; + case ProtocolInfo::CONTAINER_SET_DATA_PACKET: + $data = new ContainerSetDataPacket(); + break; + case ProtocolInfo::CONTAINER_SET_CONTENT_PACKET: + $data = new ContainerSetContentPacket(); + break; + case ProtocolInfo::CHAT_PACKET: + $data = new ChatPacket(); + break; + case ProtocolInfo::ADVENTURE_SETTINGS_PACKET: + $data = new AdventureSettingsPacket(); + break; + case ProtocolInfo::ENTITY_DATA_PACKET: + $data = new EntityDataPacket(); + break; + default: + $data = new UnknownPacket(); + $data->packetID = $pid; + break; + } + + $data->setBuffer(substr($buffer, 1)); + + return $data; + } +} \ No newline at end of file diff --git a/src/pocketmine/network/SourceInterface.php b/src/pocketmine/network/SourceInterface.php index 57e0bd8380..35954b0977 100644 --- a/src/pocketmine/network/SourceInterface.php +++ b/src/pocketmine/network/SourceInterface.php @@ -25,6 +25,7 @@ namespace pocketmine\network; use pocketmine\network\protocol\DataPacket; +use pocketmine\Player; /** * Classes that implement this interface will be able to be attached to players @@ -34,20 +35,27 @@ interface SourceInterface{ /** * Sends a DataPacket to the interface * + * @param Player $player * @param DataPacket $packet */ - public function putPacket(DataPacket $packet); - - /** - * Gets the next data packet to handle, null if none - * - * @return DataPacket - */ - public function getPacket(); + public function putPacket(Player $player, DataPacket $packet); /** * Terminates the connection + * + * @param Player $player + * @param string $reason + * */ - public function close(); + public function close(Player $player, $reason = "unknown reason"); + + /** + * @return bool + */ + public function process(); + + public function shutdown(); + + public function emergencyShutdown(); } \ No newline at end of file diff --git a/src/pocketmine/network/ThreadedHandler.php b/src/pocketmine/network/ThreadedHandler.php deleted file mode 100644 index eb9956fb95..0000000000 --- a/src/pocketmine/network/ThreadedHandler.php +++ /dev/null @@ -1,194 +0,0 @@ -server = $server; - $this->port = $port; - $this->serverip = $serverip; - $this->bandwidthUp = 0; - $this->bandwidthDown = 0; - $this->bandwidthTime = microtime(true); - $this->packets = new \Threaded(); - $this->queue = new \Threaded(); - $this->stop = false; - - //Load the classes so the Thread gets them - Info::isValid(0); - new Packet(0); - new QueryPacket(); - new RakNetPacket(0); - $this->path = \pocketmine\PATH; - $this->start(PTHREADS_INHERIT_ALL & ~PTHREADS_INHERIT_CLASSES); - } - - public function close(){ - $this->synchronized(function (){ - $this->stop = true; - socket_close($this->socket); - }); - } - - /** - * Upload speed in bytes/s - * - * @return float - */ - public function getUploadSpeed(){ - return $this->bandwidthUp / max(1, microtime(true) - $this->bandwidthTime); - } - - /** - * Download speed in bytes/s - * - * @return float - */ - public function getDownloadSpeed(){ - return $this->bandwidthDown / max(1, microtime(true) - $this->bandwidthTime); - } - - - /** - * @return Packet - */ - public function readPacket(){ - return $this->packets->shift(); - } - - /** - * @param Packet $packet - * - * @return int - */ - public function writePacket(Packet $packet){ - $this->queue[] = $packet; - - return strlen($packet->buffer); - } - - public function run(){ - require($this->path . "src/spl/SplClassLoader.php"); - $autoloader = new \SplClassLoader(); - $autoloader->add("pocketmine", array( - $this->path . "src" - )); - $autoloader->register(true); - - $this->socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); - socket_set_option($this->socket, SOL_SOCKET, SO_BROADCAST, 1); //Allow sending broadcast messages - if(@socket_bind($this->socket, $this->serverip, $this->port) === true){ - socket_set_option($this->socket, SOL_SOCKET, SO_REUSEADDR, 0); - @socket_set_option($this->socket, SOL_SOCKET, SO_SNDBUF, 1024 * 1024 * 2); //2MB - @socket_set_option($this->socket, SOL_SOCKET, SO_RCVBUF, 1024 * 1024); //1MB - }else{ - MainLogger::getLogger()->critical("**** FAILED TO BIND TO " . $this->serverip . ":" . $this->port . "!", true, true, 0); - MainLogger::getLogger()->critical("Perhaps a server is already running on that port?", true, true, 0); - exit(1); - } - socket_set_nonblock($this->socket); - - $count = 0; - while($this->stop === false){ - if($this->getPacket() === false and $this->putPacket() === false){ - ++$count; - }else{ - $count = 0; - } - if($count > 128){ - $this->wait(100000); - } - } - } - - private function putPacket(){ - if(($packet = $this->queue->shift()) instanceof Packet){ - if($packet instanceof RakNetPacket){ - $packet->encode(); - } - $this->bandwidthUp += @socket_sendto($this->socket, $packet->buffer, strlen($packet->buffer), 0, $packet->ip, $packet->port); - - return true; - } - - return false; - } - - private function getPacket(){ - $buffer = null; - $source = null; - $port = null; - $len = @socket_recvfrom($this->socket, $buffer, 65535, 0, $source, $port); - if($len === false or $len == 0){ - return false; - } - $this->bandwidthDown += $len; - $pid = ord($buffer{0}); - if(Info::isValid($pid)){ - $packet = new RakNetPacket($pid); - $packet->buffer =& $buffer; - $packet->ip = $source; - $packet->port = $port; - $packet->decode(); - }elseif($pid === 0xfe and $buffer{1} === "\xfd"){ - $packet = new QueryPacket; - $packet->ip = $source; - $packet->port = $port; - $packet->buffer =& $buffer; - }else{ - $packet = new Packet($pid); - $packet->ip = $source; - $packet->port = $port; - $packet->buffer =& $buffer; - } - $this->packets[] = $packet; - - return true; - } - -} - -?> \ No newline at end of file diff --git a/src/pocketmine/network/raknet/Info.php b/src/pocketmine/network/raknet/Info.php deleted file mode 100644 index 743ccd5a4c..0000000000 --- a/src/pocketmine/network/raknet/Info.php +++ /dev/null @@ -1,99 +0,0 @@ -packetID = (int) $packetID; - } - - public function pid(){ - return $this->packetID; - } - - protected function get($len){ - if($len < 0){ - $this->offset = strlen($this->buffer) - 1; - - return ""; - }elseif($len === true){ - return substr($this->buffer, $this->offset); - } - - $buffer = ""; - for(; $len > 0; --$len, ++$this->offset){ - $buffer .= @$this->buffer{$this->offset}; - } - - return $buffer; - } - - private function getLong($unsigned = false){ - return Binary::readLong($this->get(8), $unsigned); - } - - private function getInt(){ - return Binary::readInt($this->get(4)); - } - - private function getShort($unsigned = false){ - return Binary::readShort($this->get(2), $unsigned); - } - - private function getLTriad(){ - return Binary::readTriad(strrev($this->get(3))); - } - - private function getByte(){ - return ord($this->buffer{$this->offset++}); - } - - private function feof(){ - return !isset($this->buffer{$this->offset}); - } - - public function decode(){ - $this->offset = 1; - switch($this->packetID){ - case Info::UNCONNECTED_PING: - case Info::UNCONNECTED_PING_OPEN_CONNECTIONS: - $this->pingID = $this->getLong(); - $this->offset += 16; //Magic - break; - case Info::OPEN_CONNECTION_REQUEST_1: - $this->offset += 16; //Magic - $this->structure = $this->getByte(); - $this->mtuSize = strlen($this->get(true)); - break; - case Info::OPEN_CONNECTION_REQUEST_2: - $this->offset += 16; //Magic - $this->security = $this->get(5); - $this->clientPort = $this->getShort(false); - $this->mtuSize = $this->getShort(false); - $this->clientID = $this->getLong(); - break; - case Info::DATA_PACKET_0: - case Info::DATA_PACKET_1: - case Info::DATA_PACKET_2: - case Info::DATA_PACKET_3: - case Info::DATA_PACKET_4: - case Info::DATA_PACKET_5: - case Info::DATA_PACKET_6: - case Info::DATA_PACKET_7: - case Info::DATA_PACKET_8: - case Info::DATA_PACKET_9: - case Info::DATA_PACKET_A: - case Info::DATA_PACKET_B: - case Info::DATA_PACKET_C: - case Info::DATA_PACKET_D: - case Info::DATA_PACKET_E: - case Info::DATA_PACKET_F: - $this->seqNumber = $this->getLTriad(); - $this->data = []; - while(!$this->feof() and $this->parseDataPacket() !== false){ - - } - break; - case Info::NACK: - case Info::ACK: - $count = $this->getShort(); - $this->packets = []; - 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: - break; - } - } - - private function parseDataPacket(){ - $packetFlags = $this->getByte(); - $reliability = ($packetFlags & 0b11100000) >> 5; - $hasSplit = ($packetFlags & 0b00010000) > 0; - $length = (int) ceil($this->getShort() / 8); - if($reliability === 2 - or $reliability === 3 - or $reliability === 4 - or $reliability === 6 - or $reliability === 7 - ){ - $messageIndex = $this->getLTriad(); - }else{ - $messageIndex = false; - } - - if($reliability === 1 - or $reliability === 3 - or $reliability === 4 - or $reliability === 7 - ){ - $orderIndex = $this->getLTriad(); - $orderChannel = $this->getByte(); - }else{ - $orderIndex = false; - $orderChannel = false; - } - - if($hasSplit == true){ - $splitCount = $this->getInt(); - $splitID = $this->getShort(); - $splitIndex = $this->getInt(); - }else{ - $splitCount = false; - $splitID = false; - $splitIndex = false; - } - - if($length <= 0 - or $orderChannel >= 32 - or ($hasSplit === true and $splitIndex >= $splitCount) - ){ - return false; - }else{ - $pid = $this->getByte(); - $buffer = $this->get($length - 1); - if(strlen($buffer) < ($length - 1)){ - return false; - } - switch($pid){ - case ProtocolInfo::PING_PACKET: - $data = new PingPacket(); - break; - case ProtocolInfo::PONG_PACKET: - $data = new PongPacket(); - break; - case ProtocolInfo::CLIENT_CONNECT_PACKET: - $data = new ClientConnectPacket(); - break; - case ProtocolInfo::SERVER_HANDSHAKE_PACKET: - $data = new ServerHandshakePacket(); - break; - case ProtocolInfo::DISCONNECT_PACKET: - $data = new DisconnectPacket(); - break; - case ProtocolInfo::LOGIN_PACKET: - $data = new LoginPacket(); - break; - case ProtocolInfo::LOGIN_STATUS_PACKET: - $data = new LoginStatusPacket(); - break; - case ProtocolInfo::READY_PACKET: - $data = new ReadyPacket(); - break; - case ProtocolInfo::MESSAGE_PACKET: - $data = new MessagePacket(); - break; - case ProtocolInfo::SET_TIME_PACKET: - $data = new SetTimePacket(); - break; - case ProtocolInfo::START_GAME_PACKET: - $data = new StartGamePacket(); - break; - case ProtocolInfo::ADD_MOB_PACKET: - $data = new AddMobPacket(); - break; - case ProtocolInfo::ADD_PLAYER_PACKET: - $data = new AddPlayerPacket(); - break; - case ProtocolInfo::REMOVE_PLAYER_PACKET: - $data = new RemovePlayerPacket(); - break; - case ProtocolInfo::ADD_ENTITY_PACKET: - $data = new AddEntityPacket(); - break; - case ProtocolInfo::REMOVE_ENTITY_PACKET: - $data = new RemoveEntityPacket(); - break; - case ProtocolInfo::ADD_ITEM_ENTITY_PACKET: - $data = new AddItemEntityPacket(); - break; - case ProtocolInfo::TAKE_ITEM_ENTITY_PACKET: - $data = new TakeItemEntityPacket(); - break; - case ProtocolInfo::MOVE_ENTITY_PACKET: - $data = new MoveEntityPacket(); - break; - case ProtocolInfo::MOVE_ENTITY_PACKET_POSROT: - $data = new MoveEntityPacket_PosRot(); - break; - case ProtocolInfo::ROTATE_HEAD_PACKET: - $data = new RotateHeadPacket(); - break; - case ProtocolInfo::MOVE_PLAYER_PACKET: - $data = new MovePlayerPacket(); - break; - case ProtocolInfo::REMOVE_BLOCK_PACKET: - $data = new RemoveBlockPacket(); - break; - case ProtocolInfo::UPDATE_BLOCK_PACKET: - $data = new UpdateBlockPacket(); - break; - case ProtocolInfo::ADD_PAINTING_PACKET: - $data = new AddPaintingPacket(); - break; - case ProtocolInfo::EXPLODE_PACKET: - $data = new ExplodePacket(); - break; - case ProtocolInfo::LEVEL_EVENT_PACKET: - $data = new LevelEventPacket(); - break; - case ProtocolInfo::TILE_EVENT_PACKET: - $data = new TileEventPacket(); - break; - case ProtocolInfo::ENTITY_EVENT_PACKET: - $data = new EntityEventPacket(); - break; - case ProtocolInfo::REQUEST_CHUNK_PACKET: - $data = new RequestChunkPacket(); - break; - case ProtocolInfo::CHUNK_DATA_PACKET: - $data = new ChunkDataPacket(); - break; - case ProtocolInfo::PLAYER_EQUIPMENT_PACKET: - $data = new PlayerEquipmentPacket(); - break; - case ProtocolInfo::PLAYER_ARMOR_EQUIPMENT_PACKET: - $data = new PlayerArmorEquipmentPacket(); - break; - case ProtocolInfo::INTERACT_PACKET: - $data = new InteractPacket(); - break; - case ProtocolInfo::USE_ITEM_PACKET: - $data = new UseItemPacket(); - break; - case ProtocolInfo::PLAYER_ACTION_PACKET: - $data = new PlayerActionPacket(); - break; - case ProtocolInfo::HURT_ARMOR_PACKET: - $data = new HurtArmorPacket(); - break; - case ProtocolInfo::SET_ENTITY_DATA_PACKET: - $data = new SetEntityDataPacket(); - break; - case ProtocolInfo::SET_ENTITY_MOTION_PACKET: - $data = new SetEntityMotionPacket(); - break; - case ProtocolInfo::SET_HEALTH_PACKET: - $data = new SetHealthPacket(); - break; - case ProtocolInfo::SET_SPAWN_POSITION_PACKET: - $data = new SetSpawnPositionPacket(); - break; - case ProtocolInfo::ANIMATE_PACKET: - $data = new AnimatePacket(); - break; - case ProtocolInfo::RESPAWN_PACKET: - $data = new RespawnPacket(); - break; - case ProtocolInfo::SEND_INVENTORY_PACKET: - $data = new SendInventoryPacket(); - break; - case ProtocolInfo::DROP_ITEM_PACKET: - $data = new DropItemPacket(); - break; - case ProtocolInfo::CONTAINER_OPEN_PACKET: - $data = new ContainerOpenPacket(); - break; - case ProtocolInfo::CONTAINER_CLOSE_PACKET: - $data = new ContainerClosePacket(); - break; - case ProtocolInfo::CONTAINER_SET_SLOT_PACKET: - $data = new ContainerSetSlotPacket(); - break; - case ProtocolInfo::CONTAINER_SET_DATA_PACKET: - $data = new ContainerSetDataPacket(); - break; - case ProtocolInfo::CONTAINER_SET_CONTENT_PACKET: - $data = new ContainerSetContentPacket(); - break; - case ProtocolInfo::CHAT_PACKET: - $data = new ChatPacket(); - break; - case ProtocolInfo::ADVENTURE_SETTINGS_PACKET: - $data = new AdventureSettingsPacket(); - break; - case ProtocolInfo::ENTITY_DATA_PACKET: - $data = new EntityDataPacket(); - break; - default: - $data = new UnknownPacket(); - $data->packetID = $pid; - break; - } - $data->reliability = $reliability; - $data->hasSplit = $hasSplit; - $data->messageIndex = $messageIndex; - $data->orderIndex = $orderIndex; - $data->orderChannel = $orderChannel; - $data->splitCount = $splitCount; - $data->splitID = $splitID; - $data->splitIndex = $splitIndex; - $data->setBuffer($buffer); - $this->data[] = $data; - } - - return true; - } - - public function encode(){ - if(strlen($this->buffer) > 0){ - return; - } - $this->buffer = chr($this->packetID); - - switch($this->packetID){ - case Info::OPEN_CONNECTION_REPLY_1: - $this->buffer .= Info::MAGIC; - $this->putLong($this->serverID); - $this->putByte(0); //server security - $this->putShort($this->mtuSize); - break; - case Info::OPEN_CONNECTION_REPLY_2: - $this->buffer .= Info::MAGIC; - $this->putLong($this->serverID); - $this->putShort($this->serverPort); - $this->putShort($this->mtuSize); - $this->putByte(0); //Server security - break; - case Info::INCOMPATIBLE_PROTOCOL_VERSION: - $this->putByte(Info::STRUCTURE); - $this->buffer .= Info::MAGIC; - $this->putLong($this->serverID); - break; - case Info::UNCONNECTED_PONG: - case Info::ADVERTISE_SYSTEM: - $this->putLong($this->pingID); - $this->putLong($this->serverID); - $this->buffer .= Info::MAGIC; - $this->putString($this->serverType); - break; - case Info::DATA_PACKET_0: - case Info::DATA_PACKET_1: - case Info::DATA_PACKET_2: - case Info::DATA_PACKET_3: - case Info::DATA_PACKET_4: - case Info::DATA_PACKET_5: - case Info::DATA_PACKET_6: - case Info::DATA_PACKET_7: - case Info::DATA_PACKET_8: - case Info::DATA_PACKET_9: - case Info::DATA_PACKET_A: - case Info::DATA_PACKET_B: - case Info::DATA_PACKET_C: - case Info::DATA_PACKET_D: - case Info::DATA_PACKET_E: - case Info::DATA_PACKET_F: - $this->putLTriad($this->seqNumber); - foreach($this->data as $pk){ - $this->encodeDataPacket($pk); - } - break; - case Info::NACK: - case Info::ACK: - $payload = ""; - $records = 0; - $pointer = 0; - sort($this->packets, SORT_NUMERIC); - $max = count($this->packets); - - while($pointer < $max){ - $type = true; - $curr = $start = $this->packets[$pointer]; - for($i = $start + 1; $i < $max; ++$i){ - $n = $this->packets[$i]; - if(($n - $curr) === 1){ - $curr = $end = $n; - $type = false; - $pointer = $i + 1; - }else{ - break; - } - } - ++$pointer; - if($type === false){ - $payload .= "\x00"; - $payload .= strrev(Binary::writeTriad($start)); - $payload .= strrev(Binary::writeTriad($end)); - }else{ - $payload .= Binary::writeBool(true); - $payload .= strrev(Binary::writeTriad($start)); - } - ++$records; - } - $this->putShort($records); - $this->buffer .= $payload; - break; - default: - - } - - } - - private function encodeDataPacket(DataPacket $pk){ - $this->putByte(($pk->reliability << 5) | ($pk->hasSplit > 0 ? 0b00010000 : 0)); - $this->putShort(strlen($pk->buffer) << 3); - if($pk->reliability === 2 - or $pk->reliability === 3 - or $pk->reliability === 4 - or $pk->reliability === 6 - or $pk->reliability === 7 - ){ - $this->putLTriad($pk->messageIndex); - } - - if($pk->reliability === 1 - or $pk->reliability === 3 - or $pk->reliability === 4 - or $pk->reliability === 7 - ){ - $this->putLTriad($pk->orderIndex); - $this->putByte($pk->orderChannel); - } - - if($pk->hasSplit === true){ - $this->putInt($pk->splitCount); - $this->putShort($pk->splitID); - $this->putInt($pk->splitIndex); - } - - $this->buffer .= $pk->buffer; - } - - protected function put($str){ - $this->buffer .= $str; - } - - protected function putLong($v){ - $this->buffer .= Binary::writeLong($v); - } - - protected function putInt($v){ - $this->buffer .= Binary::writeInt($v); - } - - protected function putShort($v){ - $this->buffer .= Binary::writeShort($v); - } - - protected function putTriad($v){ - $this->buffer .= Binary::writeTriad($v); - } - - protected function putLTriad($v){ - $this->buffer .= strrev(Binary::writeTriad($v)); - } - - protected function putByte($v){ - $this->buffer .= chr($v); - } - - protected function putString($v){ - $this->putShort(strlen($v)); - $this->put($v); - } - - public function __destruct(){ - } -} \ No newline at end of file diff --git a/src/raklib b/src/raklib index bf180fdfa7..bb63be6043 160000 --- a/src/raklib +++ b/src/raklib @@ -1 +1 @@ -Subproject commit bf180fdfa72ed4893c16054768d9564487c36d26 +Subproject commit bb63be60432e7078b81f3681030e5bbb4f9f9004