package tc.oc.commons.bukkit.teleport; import java.util.UUID; import javax.annotation.Nullable; import javax.inject.Inject; import javax.inject.Singleton; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.TranslatableComponent; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionDefault; import tc.oc.api.docs.Server; import tc.oc.api.docs.virtual.ServerDoc; import tc.oc.api.users.UserService; import tc.oc.commons.bukkit.chat.Audiences; import tc.oc.commons.bukkit.chat.NameStyle; import tc.oc.commons.bukkit.chat.PlayerComponent; import tc.oc.commons.bukkit.event.PlayerServerChangeEvent; import tc.oc.commons.bukkit.format.ServerFormatter; import tc.oc.commons.bukkit.nick.IdentityProvider; import tc.oc.commons.core.chat.Audience; import tc.oc.commons.core.chat.Component; import tc.oc.commons.core.chat.NullAudience; @Singleton public class Teleporter { public static final Permission PERMISSION = new Permission("ocn.teleport", PermissionDefault.FALSE); public static final Permission PERMISSION_OTHERS = new Permission("ocn.teleport.others", PermissionDefault.OP); public static final String CROSS_DATACENTER_PERMISSION = "server.cross-datacenter"; private final UserService userService; private final IdentityProvider identityProvider; private final Audiences audiences; private final PlayerServerChanger playerServerChanger; private final Server localServer; @Inject Teleporter(UserService userService, IdentityProvider identityProvider, Audiences audiences, PlayerServerChanger playerServerChanger, Server localServer) { this.userService = userService; this.identityProvider = identityProvider; this.audiences = audiences; this.playerServerChanger = playerServerChanger; this.localServer = localServer; } public boolean isConnectable(Server server) { return server.online() && server.visibility() != ServerDoc.Visibility.PRIVATE && server.role() != ServerDoc.Role.BUNGEE && server.network().equals(localServer.network()) && server.datacenter().equals(localServer.datacenter()); } public boolean isVisible(Server server) { return isConnectable(server) && server.visibility() == ServerDoc.Visibility.PUBLIC; } public boolean isLocal(@Nullable ServerDoc.Identity destinationServer) { return destinationServer == null ? localServer.role() == ServerDoc.Role.LOBBY : localServer.bungee_name().equals(destinationServer.bungee_name()); } public void showCurrentServer(CommandSender viewer) { showCurrentServer(audiences.get(viewer)); } public void showCurrentServer(Audience audience) { audience.sendMessage(new Component( new TranslatableComponent( "command.server.currentServer", ServerFormatter.light.nameWithDatacenter(localServer) ), ChatColor.DARK_PURPLE )); audience.sendMessage(new Component(new TranslatableComponent("command.server.switchPrompt"), ChatColor.GREEN)); } public void localTeleport(Player traveler, @Nullable Player destinationPlayer) { if(destinationPlayer != null && traveler.hasPermission(PERMISSION)) { audiences.get(traveler).sendMessage(new Component( new TranslatableComponent("command.server.teleporting", new PlayerComponent(identityProvider.currentIdentity(destinationPlayer), NameStyle.VERBOSE)), ChatColor.DARK_PURPLE )); traveler.teleport(destinationPlayer); } } public void localTeleport(Player traveler, @Nullable UUID destinationPlayer) { if(destinationPlayer != null && traveler.hasPermission(PERMISSION)) { localTeleport(traveler, traveler.getServer().getPlayer(destinationPlayer)); } } public void remoteTeleport(Player traveler, ServerDoc.Identity destinationServer, @Nullable UUID destinationPlayer) { if(traveler.hasPermission(PERMISSION)) { Player target = destinationPlayer == null ? null : traveler.getServer().getPlayer(destinationPlayer); if(target != null) { localTeleport(traveler, target); } else if (!isLocal(destinationServer)) { // TeleportListener will receive this message and call sendToServer userService.requestTeleport(traveler.getUniqueId(), destinationServer, destinationPlayer); } } } public ListenableFuture<?> remoteTeleport(Player traveler, @Nullable ServerDoc.Identity server) { return remoteTeleport(traveler, server, false); } public ListenableFuture<?> remoteTeleport(Player traveler, @Nullable ServerDoc.Identity server, boolean quiet) { return server != null ? remoteTeleport(traveler, server.datacenter(), server.name(), server.bungee_name(), quiet) : sendToLobby(traveler, quiet); } public ListenableFuture<?> remoteTeleport(Player traveler, @Nullable String datacenter, @Nullable String serverName, @Nullable String bungeeName) { return remoteTeleport(traveler, datacenter, serverName, bungeeName, false); } public ListenableFuture<?> remoteTeleport(Player traveler, @Nullable String datacenter, @Nullable String serverName, @Nullable String bungeeName, boolean quiet) { final Audience audience = quiet ? NullAudience.INSTANCE : audiences.get(traveler); if(datacenter == null || !traveler.hasPermission(CROSS_DATACENTER_PERMISSION)) { datacenter = localServer.datacenter(); } final BaseComponent fullName = ServerFormatter.light.nameWithDatacenter(datacenter, bungeeName, serverName, bungeeName == null); if((bungeeName == null && localServer.role() == ServerDoc.Role.LOBBY) || (bungeeName != null && bungeeName.equals(localServer.bungee_name()))) { showCurrentServer(audience); return Futures.immediateFuture(null); } PlayerServerChangeEvent event = new PlayerServerChangeEvent(traveler, datacenter, bungeeName, new TranslatableComponent("servers.cannotChange")); traveler.getServer().getPluginManager().callEvent(event); if(event.isCancelled()) { if(event.getCancelMessage() != null) { audience.sendWarning(event.getCancelMessage(), false); } return Futures.immediateCancelledFuture(); } audience.sendMessage(new Component(new TranslatableComponent("command.server.teleporting", fullName), ChatColor.DARK_PURPLE)); return playerServerChanger.sendPlayerToServer(traveler, bungeeName, quiet); } public ListenableFuture<?> sendToLobby(Player player, @Nullable String datacenter, boolean quiet) { return remoteTeleport(player, datacenter, null, null, quiet); } public ListenableFuture<?> sendToLobby(Player player, @Nullable String datacenter) { return sendToLobby(player, datacenter, false); } public ListenableFuture<?> sendToLobby(Player player, boolean quiet) { return sendToLobby(player, null, quiet); } }