package tc.oc.commons.bungee.listeners; import java.util.Optional; import java.util.Set; import java.util.logging.Logger; import javax.inject.Inject; import javax.inject.Singleton; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.event.ServerConnectEvent; import net.md_5.bungee.api.event.ServerKickEvent; import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.event.EventHandler; import tc.oc.api.docs.Server; import tc.oc.commons.bungee.servers.LobbyTracker; import tc.oc.commons.core.chat.Component; import tc.oc.commons.core.logging.Loggers; import tc.oc.commons.core.plugin.PluginFacet; import static tc.oc.commons.core.stream.Collectors.toImmutableSet; /** * Routes players to lobbies, and handles a few other things * related to switching servers. */ @Singleton public class PlayerServerRouter implements Listener, PluginFacet { private static final String KICK_COLOR_CODES = ChatColor.BLACK.toString() + ChatColor.RED.toString(); private final Logger logger; private final Server localServer; private final LobbyTracker lobbyTracker; @Inject PlayerServerRouter(Loggers loggers, Server localServer, LobbyTracker lobbyTracker) { this.logger = loggers.get(getClass()); this.localServer = localServer; this.lobbyTracker = lobbyTracker; } @EventHandler public void connect(final ServerConnectEvent event) { // don't send "could not connect to server you're already on" message if(event.getPlayer().getServer() != null && event.getPlayer().getServer().getInfo().equals(event.getTarget())) { event.setCancelled(true); } if(event.getTarget().getName().equals("default")) { final int proto = event.getPlayer().getProtocolVersion(); final Optional<ServerInfo> lobby = lobbyTracker.chooseLobby(proto); if(lobby.isPresent()) { event.setTarget(lobby.get()); } else { final Set<Integer> supported = lobbyTracker.supportedProtocols().collect(toImmutableSet()); if(!supported.isEmpty()) { event.getPlayer().disconnect( new Component("Please connect with Minecraft ", ChatColor.RED) .extra(PingListener.describeVersionRange(supported)) ); } } } event.setFakeUsername(localServer.fake_usernames().get(event.getPlayer().getUniqueId())); } @EventHandler public void reroute(final ServerKickEvent event) { if(event.getKickReason().contains(KICK_COLOR_CODES)) { event.getPlayer().disconnect(event.getKickReason()); } else { event.setCancelled(true); if(event.getState() == ServerKickEvent.State.CONNECTED) { // Player was kicked off a server they were already connected to // Send them to the lobby, and make sure it's not the server they just left lobbyTracker.chooseLobby(event.getPlayer().getProtocolVersion(), event.getKickedFrom()) .ifPresent(event::setCancelServer); } else if(event.getState() == ServerKickEvent.State.CONNECTING) { // Player was kicked when trying to connect to a server if(event.getPlayer().getServer() != null) { // If they are currently on a different server, keep them there event.setCancelServer(event.getPlayer().getServer().getInfo()); for(String message : event.getKickReason().split("\n\n")) { event.getPlayer().sendMessage(message); } } else { // Otherwise they were trying to connect to the network, so don't let them event.getPlayer().disconnect(event.getKickReason()); } } } } }