Is that good code, what do you think? Spoiler PHP: <?php/* * FastTransfer plugin for PocketMine-MP * Copyright (C) 2015 Shoghi Cervantes <https://github.com/shoghicp/FastTransfer> * * 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 * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */namespace shoghicp\FastTransfer;use pocketmine\command\Command;use pocketmine\command\CommandSender;use pocketmine\event\TranslationContainer;use pocketmine\event\player\PlayerRespawnEvent;use pocketmine\event\player\PlayerJoinEvent;use pocketmine\event\server\DataPacketSendEvent;use pocketmine\network\protocol\AdventureSettingsPacket;use pocketmine\event\server\DataPacketReceiveEvent;use pocketmine\network\protocol\AnimatePacket;use pocketmine\network\protocol\BatchPacket;use pocketmine\network\protocol\ContainerSetContentPacket;use pocketmine\network\protocol\DataPacket;use pocketmine\network\protocol\DisconnectPacket;use pocketmine\network\protocol\EntityEventPacket;use pocketmine\network\protocol\FullChunkDataPacket;use pocketmine\network\protocol\Info;use pocketmine\network\protocol\PlayStatusPacket;use pocketmine\network\protocol\RespawnPacket;use pocketmine\network\protocol\TextPacket;use pocketmine\network\protocol\MoveEntityPacket;use pocketmine\network\protocol\MovePlayerPacket;use pocketmine\network\protocol\SetDifficultyPacket;use pocketmine\network\protocol\SetEntityMotionPacket;use pocketmine\network\protocol\SetHealthPacket;use pocketmine\network\protocol\SetSpawnPositionPacket;use pocketmine\network\protocol\SetTimePacket;use pocketmine\network\protocol\StartGamePacket;use pocketmine\network\protocol\TakeItemEntityPacket;use pocketmine\network\protocol\UpdateBlockPacket;use pocketmine\network\Network;use pocketmine\Player;use pocketmine\plugin\PluginBase;use pocketmine\utils\TextFormat;class FastTransfer extends PluginBase{ private $lookup = []; private $transferred = array(); /** * Will transfer a connected player to another server. * This will trigger PlayerTransferEvent * * Player transfer might not be instant if you use a DNS address instead of an IP address * * @param Player $player * @param string $address * @param int $port * @param string $message If null, ignore message * * @return bool */ public function transferPlayer(Player $player, $address, $port = 19132, $message = "You are being transferred"){ $ev = new PlayerTransferEvent($player, $address, $port, $message); $this->getServer()->getPluginManager()->callEvent($ev); if($ev->isCancelled()){ return false; } $ip = $this->lookupAddress($ev->getAddress()); if($ip === null){ return false; } if($message !== null and $message !== ""){ $player->sendMessage($message); } $packet = new StrangePacket(); $packet->address = $ip; $packet->port = $ev->getPort(); $player->dataPacket($packet->setChannel(Network::CHANNEL_PRIORITY)); $this->transferred[$player->getName()] = $player; return true; } /** * Clear the DNS lookup cache. */ public function cleanLookupCache(){ $this->lookup = []; } /** * VERY HARD FastTransfer hack: not fully disconnect player */ public function onSend(DataPacketSendEvent $event) { if(in_array($event->getPlayer(), $this->transferred)){ $event->setCancelled(true); } } /** * VERY HARD FastTransfer hack: connect player */ public function onReceive(DataPacketReceiveEvent $event) { if(in_array($event->getPlayer(), $this->transferred) && $event->getPacket()->pid() === Info::LOGIN_PACKET){ $event->setCancelled(true); $pk = new PlayStatusPacket(); $pk->status = PlayStatusPacket::LOGIN_SUCCESS; $event->getPlayer()->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY)); $spawnPosition = $event->getPlayer()->getSpawn(); $pk = new StartGamePacket(); $pk->seed = -1; $pk->x = $event->getPlayer()->x; $pk->y = $event->getPlayer()->y; $pk->z = $event->getPlayer()->z; $pk->spawnX = (int) $spawnPosition->x; $pk->spawnY = (int) $spawnPosition->y; $pk->spawnZ = (int) $spawnPosition->z; $pk->generator = 1; //0 old, 1 infinite, 2 flat $pk->gamemode = $event->getPlayer()->getGamemode() & 0x01; $pk->eid = 0; $event->getPlayer()->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY)); $pk = new SetTimePacket(); $pk->time = $event->getPlayer()->getLevel()->getTime(); $pk->started = $event->getPlayer()->getLevel()->stopTime == false; $event->getPlayer()->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY)); $pk = new SetSpawnPositionPacket(); $pk->x = (int) $spawnPosition->x; $pk->y = (int) $spawnPosition->y; $pk->z = (int) $spawnPosition->z; $event->getPlayer()->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY)); $pk = new SetHealthPacket(); $pk->health = $event->getPlayer()->getHealth(); $event->getPlayer()->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY)); $pk = new SetDifficultyPacket(); $pk->difficulty = $this->getServer()->getDifficulty(); $event->getPlayer()->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY)); if($event->getPlayer()->getGaamemode() === Player::SPECTATOR){ $pk = new ContainerSetContentPacket(); $pk->windowid = ContainerSetContentPacket::SPECIAL_CREATIVE; $event->getPlayer()->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY)); }else{ $pk = new ContainerSetContentPacket(); $pk->windowid = ContainerSetContentPacket::SPECIAL_CREATIVE; $pk->slots = Item::getCreativeItems(); $event->getPlayer()->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY)); } $pk = new SetTimePacket(); $pk->time = $event->getPlayer()->getLevel->getTime(); $pk->started = $event->getPlayer()->getLevel()->stopTime == false; $event->getPlayer()->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY)); $pos = $event->getPlayer()->getLevel()->getSafeSpawn($event->getPlayer()); $this->getServer()->getPluginManager()->callEvent($ev = new PlayerRespawnEvent($this, $pos)); $pos = $ev->getRespawnPosition(); $pk = new RespawnPacket(); $pk->x = $pos->x; $pk->y = $pos->y; $pk->z = $pos->z; $event->getPlayer()->dataPacket($pk->setChannel(Network::CHANNEL_WORLD_CHUNKS)); $pk = new PlayStatusPacket(); $pk->status = PlayStatusPacket::PLAYER_SPAWN; $event->getPlayer()->dataPacket($pk->setChannel(Network::CHANNEL_WORLD_CHUNKS)); $this->getServer()->getPluginManager()->callEvent($ev = new PlayerJoinEvent($event->getPlayer(), new TranslationContainer(TextFormat::YELLOW . "%multiplayer.player.joined", [ $event->getPlayer()->getDisplayName() ]) )); if(strlen(trim($ev->getJoinMessage())) > 0){ $this->getServer()->broadcastMessage($ev->getJoinMessage()); } unset($this->transferred[$event->getPlayer()->getName()]) } } public function onCommand(CommandSender $sender, Command $command, $label, array $args){ if($label === "transfer"){ if(count($args) < 2 or count($args) > 3 or (count($args) === 2 and !($sender instanceof Player))){ $sender->sendMessage(new TranslationContainer("commands.generic.usage", [$command->getUsage()])); return true; } /** @var Player $target */ $target = $sender; if(count($args) === 3){ $target = $sender->getServer()->getPlayer($args[0]); $address = $args[1]; $port = (int) $args[2]; }else{ $address = $args[0]; $port = (int) $args[1]; } if($target === null){ $sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.player.notFound")); return true; } $sender->sendMessage("Transferring player " . $target->getDisplayName() . " to $address:$port"); if(!$this->transferPlayer($target, $address, $port)){ $sender->sendMessage(TextFormat::RED . "An error occurred during the transfer"); } return true; } return false; } /** * @param $address * * @return null|string */ private function lookupAddress($address){ //IP address if(preg_match("/^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$/", $address) > 0){ return $address; } $address = strtolower($address); if(isset($this->lookup[$address])){ return $this->lookup[$address]; } $host = gethostbyname($address); if($host === $address){ return null; } $this->lookup[$address] = $host; return $host; }}
My idea, no, its not... Why you need to use soooo much Packets?... I'm sure that this code is extracted from others server plugin... It handles lot of extra (not transfer player required) thing... *Correct me if im wrong
And... there's unused function... PHP: public function cleanLookupCache(){ $this->lookup = [];} Hahaha, i can confirm that u 100% copying others code and merging it anyway u like xD
I I think, if I close RakLib, player is disconnect, because closeSession method close player instruction, and close method of Player can kick Player, if it already transferred. Packets I extracted from Player.php, from handleDataPacket function
I have no idea why you're doing this... PEMapModder already show us a way to temporary "fix" it by closing RakLib connection...
It is... Check my server.. LOL... Yes, its not 100% fixed.. But at least better.. There's no permanent/fully working fix of Fasttransfer for PM1.5 (MCPE 0.12.x) Just give it up and look foward to MCPE 0.13.x
Noob question - Spoiler: Tap here How do we actually implement this code? Do we just make it into a new plugin and make @MrGenga's or @PEMapModder's code the main class? That's what I'm thinking. What's your answer?
Why it not works? Player transferred, but not closed from RakLib. P.S. Edited FT main class PHP: <?php/* * FastTransfer plugin for PocketMine-MP * Copyright (C) 2015 Shoghi Cervantes <https://github.com/shoghicp/FastTransfer> * * 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 * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */namespace shoghicp\FastTransfer;use pocketmine\command\Command;use pocketmine\command\CommandSender;use pocketmine\event\TranslationContainer;use pocketmine\network\Network;use pocketmine\network\RakLibInterface;use pocketmine\Player;use pocketmine\plugin\PluginBase;use pocketmine\utils\TextFormat;class FastTransfer extends PluginBase{ private $lookup = []; /** * Will transfer a connected player to another server. * This will trigger PlayerTransferEvent * * Player transfer might not be instant if you use a DNS address instead of an IP address * * @param Player $player * @param string $address * @param int $port * @param string $message If null, ignore message * * @return bool */ public function transferPlayer(Player $player, $address, $port = 19132, $message = "You are being transferred"){ $ev = new PlayerTransferEvent($player, $address, $port, $message); $this->getServer()->getPluginManager()->callEvent($ev); if($ev->isCancelled()){ return false; } $ip = $this->lookupAddress($ev->getAddress()); if($ip === null){ return false; } if($message !== null and $message !== ""){ $player->sendMessage($message); } $packet = new StrangePacket(); $packet->address = $ip; $packet->port = $ev->getPort(); $player->dataPacket($packet->setChannel(Network::CHANNEL_PRIORITY)); $rakLib = null; foreach($this->getServer()->getNetwork()-> getInterfaces() as $interface) { if($interface instanceof RakLibInterface) { $raklib = $interface; break; } } if($rakLib == null){ return false; } $identifier = $player ->getAddress () . ":" . $player->getPort(); $rakLib->closeSession($identifier, "transfer"); return true; } /** * Clear the DNS lookup cache. */ public function cleanLookupCache(){ $this->lookup = []; } public function onCommand(CommandSender $sender, Command $command, $label, array $args){ if($label === "transfer"){ if(count($args) < 2 or count($args) > 3 or (count($args) === 2 and !($sender instanceof Player))){ $sender->sendMessage(new TranslationContainer("commands.generic.usage", [$command->getUsage()])); return true; } /** @var Player $target */ $target = $sender; if(count($args) === 3){ $target = $sender->getServer()->getPlayer($args[0]); $address = $args[1]; $port = (int) $args[2]; }else{ $address = $args[0]; $port = (int) $args[1]; } if($target === null){ $sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.player.notFound")); return true; } $sender->sendMessage("Transferring player " . $target->getDisplayName() . " to $address:$port"); if(!$this->transferPlayer($target, $address, $port)){ $sender->sendMessage(TextFormat::RED . "An error occurred during the transfer"); } return true; } return false; } /** * @param $address * * @return null|string */ private function lookupAddress($address){ //IP address if(preg_match("/^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$/", $address) > 0){ return $address; } $address = strtolower($address); if(isset($this->lookup[$address])){ return $this->lookup[$address]; } $host = gethostbyname($address); if($host === $address){ return null; } $this->lookup[$address] = $host; return $host; }}