As we all know, 0.12.1 has many issues, and one of the significant ones is the malfunctioning of the FastTransfer packet - 0x1b. The issue is that the client does not close the session after joining another server, and so the client continues to accept data from the server. And if you explicitly kick the player on the old server, you will find that the player quits the new server as well (at least visually). I have worked out a temporary "solution" to this problem: PHP: // SKIPPED: code to transfer player away by sending packet, i.e. calling the FastTransfer API function.// find out the RakLib interface, which is the network interface that MCPE players connect withforeach($server->getNetwork()->getInterfaces() as $interface){ if($interface instanceof RakLibInterface){ $raklib = $interface; break; }}if(!isset($rakLib)){ return;}// calculate the identifier for the player used by RakLib$identifier = $player->getAddress() . ":" . $player->getPort();// this method call is the most important one - it sends some signal to RakLib that makes it think that the client has clicked the "Quit to Title" button (or timed out). Some RakLib internal stuff will then tell PocketMine that the player has quitted.$rakLib->closeSession($identifier, "transfer");
Note that doing this has a lot of side effects. Technically: Players still connect to your server through an open socket, and they may still send data. This may let you understand more clearly: Every client you transfer will DoS you. Transferring many clients is equivalent to asking them to DDoS you.
Do you know what DDoS means? DDoS means to have a large number of clients connecting to a server from different sources, making your server slow down and become almsot nonfunctional. How would those so-called DDoS protection services know if they are normal clients or attackers? They are not DDoS, but they still send a lot of useless data to the server, so it is semi DDoS.
The problem itself is in the client, so all the people asking about other server software not being buggy on transfer don't understand the problem. Also remember that this method is hacky and might go away (that's why it's a plugin and not a core feature) so don't base your server around this!
The code I posted was already full code. And I won't post any phars, because I don't really encourage you to use it unless you know very clearly the consequences of doing so, which you most likely don't if you are unable to apply the changes yourself. And again, this is a temporary "solution", not a fix. This only hides the problem from your eyes, but the 80% of the problem's negative effects still exists. And it works. I am using it on LegionPE. If you need proof: https://github.com/LegionPE/LegionPE-Theta-Base/blob/master/src/legionpe/theta/BasePlugin.php#L523 However, my code is slightly different from what you will use, so don't copy it. You can copy it, but it will surely "not work" (it is too vague to say "not work"; it can mean many things). And I won't help you fix it if you just copy LegionPE-Theta-Base. Read the first line of my code: // SKIPPE code to transfer players away using FastTransfer API
Do you have any practical idea of what the size of the "DDoS attack" is? You say they "may still send data", do you happen to know when and how much they send? Are they sending every packet to every server they have connected to, or just occasional packets, or are you just saying that they might theoretically sometimes do it, but generally stick with their current server?
A small scale I suppose. Every client you send assume you are still connected, so they keep sending data they expect to send. According to @shoghicp, for reasons that I don't understand, clients sometimes think that they are servers and even send chunks packets. Although they are not connected and hence packets are internally ignored, they can still significantly affect server performance if the server-to-players ratio is not high enough. Moreover, as clients are temporarily connected to the old server, they cannot be transferred back according to testing.
It Work PHP: private function transferPlayer0(Player $player, $ip, $port){ $packet = new TransferPacket(); $packet->address = $this->getHostByName($ip); $packet->port = $port; $player->dataPacket($packet); $this->removePlayer($player); $this->removeOnlinePlayer($player); $this->removePlayerListData($player->getUniqueId(), [$player]); $rakLib = null; foreach($this->getServer()->getNetwork()->getInterfaces() as $interface) { if($interface instanceof RakLibInterface) { $raklib = $interface; break; } } if(!isset($rakLib)){ return; } $identifier = $player->getAddress () . ":" . $player->getPort(); $rakLib->closeSession($identifier, "transfer"); $this->getServer()->removeInterface($identifier); } public function removePlayer(Player $player){ if(isset($this->identifiers[$hash = spl_object_hash($player)])){ $identifier = $this->identifiers[$hash]; unset($this->players[$identifier]); unset($this->identifiers[$hash]); return; } foreach($this->players as $identifier => $p){ if($player === $p){ unset($this->players[$identifier]); unset($this->identifiers[spl_object_hash($player)]); break; } } } public function removePlayerListData(UUID $uuid, array $players = null){ $pk = new PlayerListPacket(); $pk->type = PlayerListPacket::TYPE_REMOVE; $pk->entries[] = [$uuid]; Server::broadcastPacket($players === null ? $this->playerList : $players, $pk); } public function removeOnlinePlayer(Player $player){ if(isset($this->playerList[$player->getRawUniqueId()])){ unset($this->playerList[$player->getRawUniqueId()]); $pk = new PlayerListPacket(); $pk->type = PlayerListPacket::TYPE_REMOVE; $pk->entries[] = [$player->getUniqueId()]; Server::broadcastPacket($this->playerList, $pk); } } Cr.PEMapModder and Guillaume351
You don't need to remove player from player list. Closing the RakLib session already disconnects the player properly.