package tc.oc.commons.bukkit.teleport; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import javax.annotation.Nullable; import javax.inject.Inject; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; import net.md_5.bungee.api.ChatColor; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.metadata.MetadataValue; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.messaging.Messenger; import tc.oc.api.docs.Server; import tc.oc.api.docs.virtual.ServerDoc; import tc.oc.commons.core.plugin.PluginFacet; public class PlayerServerChanger implements PluginFacet, Listener { private static final String PLUGIN_CHANNEL = "BungeeCord"; private static final String METADATA_KEY = "QuitFuture"; private final Plugin plugin; private final Messenger messenger; private final Server localServer; @Inject PlayerServerChanger(Plugin plugin, Messenger messenger, Server localServer) { this.plugin = plugin; this.messenger = messenger; this.localServer = localServer; } @Override public void enable() { messenger.registerOutgoingPluginChannel(plugin, PLUGIN_CHANNEL); } @Override public void disable() { messenger.unregisterOutgoingPluginChannel(plugin, PLUGIN_CHANNEL); } private ListenableFuture<?> quitFuture(Player player) { if(player.isOnline()) { final SettableFuture<?> future = SettableFuture.create(); player.setMetadata(METADATA_KEY, new FixedMetadataValue(plugin, future)); return future; } else { return Futures.immediateFuture(null); } } @EventHandler(priority = EventPriority.LOWEST) public void onQuit(PlayerQuitEvent event) { final MetadataValue future = event.getPlayer().getMetadata(METADATA_KEY, plugin); if(future != null) { ((SettableFuture) future.value()).set(null); } } public ListenableFuture<?> sendPlayerToLobby(Player player, boolean quiet) { return sendPlayerToServer(player, (String) null, quiet); } public ListenableFuture<?> sendPlayerToServer(Player player, @Nullable ServerDoc.BungeeName server, boolean quiet) { return sendPlayerToServer(player, server == null ? null : server.bungee_name(), quiet); } public ListenableFuture<?> sendPlayerToServer(Player player, @Nullable String bungeeName, boolean quiet) { if(localServer.bungee_name().equals(bungeeName) || (localServer.role() == ServerDoc.Role.LOBBY && bungeeName == null)) { return Futures.immediateFuture(null); } final ByteArrayOutputStream message = new ByteArrayOutputStream(); final DataOutputStream out = new DataOutputStream(message); try { out.writeUTF(quiet ? "ConnectQuiet" : "Connect"); out.writeUTF(bungeeName == null ? "default" : bungeeName); } catch(IOException e) { return Futures.immediateFailedFuture(e); } player.sendPluginMessage(plugin, PLUGIN_CHANNEL, message.toByteArray()); return quitFuture(player); } public ListenableFuture<?> kickPlayer(Player player, String message) { // Magic color sequence signals Bungee to disconnect the player player.kickPlayer(ChatColor.BLACK.toString() + ChatColor.RED + ChatColor.RESET + message); return quitFuture(player); } }