diff --git a/SubServers.Bungee/common/src/net/ME1312/SubServers/Bungee/Library/Fallback/FallbackState.java b/SubServers.Bungee/common/src/net/ME1312/SubServers/Bungee/Library/Fallback/FallbackState.java new file mode 100644 index 00000000..55ea58e3 --- /dev/null +++ b/SubServers.Bungee/common/src/net/ME1312/SubServers/Bungee/Library/Fallback/FallbackState.java @@ -0,0 +1,72 @@ +package net.ME1312.SubServers.Bungee.Library.Fallback; + +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.config.ServerInfo; + +import java.util.*; + +/** + * Fallback Player State Class + */ +public class FallbackState { + public final UUID player; + public final LinkedList names; + public final LinkedList servers; + public final BaseComponent[] reason; + private Map map; + private Timer finish; + + /** + * Smart Fallback State Container + * + * @param player Player + * @param servers Fallback Servers + * @param reason Original Disconnect Reason + */ + public FallbackState(UUID player, Map servers, BaseComponent... reason) { + this.player = player; + this.map = servers; + this.names = new LinkedList<>(servers.keySet()); + this.servers = new LinkedList<>(servers.values()); + this.reason = reason; + } + + /** + * Use a server + * + * @param name Server name to remove + */ + public void remove(String name) { + servers.remove(map.get(name)); + names.remove(name); + map.remove(name); + } + + /** + * Use a server + * + * @param server Server to remove + */ + public void remove(ServerInfo server) { + map.remove(server.getName()); + names.remove(server.getName()); + servers.remove(server); + } + + /** + * Finish the process + * + * @param callback Finishing callback + * @param delay Delay for determining stability + */ + public void done(Runnable callback, long delay) { + if (finish != null) finish.cancel(); + (finish = new Timer("SubServers.Bungee::Fallback_Limbo_Timer(" + player + ')')).schedule(new TimerTask() { + @Override + public void run() { + if (callback != null) callback.run(); + finish.cancel(); + } + }, delay); + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/SubProxy.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/SubProxy.java index 0eaa0d23..78371583 100644 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/SubProxy.java +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/SubProxy.java @@ -25,6 +25,7 @@ import net.ME1312.SubServers.Bungee.Library.Compatibility.Plugin; import net.ME1312.SubServers.Bungee.Library.ConfigUpdater; import net.ME1312.SubServers.Bungee.Library.Exception.InvalidHostException; import net.ME1312.SubServers.Bungee.Library.Exception.InvalidServerException; +import net.ME1312.SubServers.Bungee.Library.Fallback.FallbackState; import net.ME1312.SubServers.Bungee.Library.Fallback.SmartFallback; import net.ME1312.SubServers.Bungee.Library.Metrics; import net.ME1312.SubServers.Bungee.Network.Packet.PacketExDisconnectPlayer; @@ -75,7 +76,7 @@ public final class SubProxy extends BungeeCommon implements Listener { public final HashMap rPlayerLinkS = new HashMap(); public final HashMap rPlayerLinkP = new HashMap(); public final HashMap rPlayers = new HashMap(); - private final HashMap> fallbackLimbo = new HashMap>(); + private final HashMap fallback = new HashMap(); public final PrintStream out; public final UniversalFile dir = new UniversalFile(new File(System.getProperty("user.dir"))); @@ -947,8 +948,8 @@ public final class SubProxy extends BungeeCommon implements Listener { } if (!e.getTarget().canAccess(e.getPlayer())) { - if (e.getPlayer().getServer() == null || fallbackLimbo.keySet().contains(e.getPlayer().getUniqueId())) { - if (!fallbackLimbo.keySet().contains(e.getPlayer().getUniqueId()) || fallbackLimbo.get(e.getPlayer().getUniqueId()).contains(e.getTarget())) { + if (e.getPlayer().getServer() == null || fallback.containsKey(e.getPlayer().getUniqueId())) { + if (!fallback.containsKey(e.getPlayer().getUniqueId()) || fallback.get(e.getPlayer().getUniqueId()).names.contains(e.getTarget().getName())) { ServerKickEvent kick = new ServerKickEvent(e.getPlayer(), e.getTarget(), new BaseComponent[]{ new TextComponent(getTranslation("no_server_permission")) }, null, ServerKickEvent.State.CONNECTING); @@ -960,16 +961,17 @@ public final class SubProxy extends BungeeCommon implements Listener { e.getPlayer().sendMessage(getTranslation("no_server_permission")); e.setCancelled(true); } - } else if (e.getPlayer().getServer() != null && !fallbackLimbo.keySet().contains(e.getPlayer().getUniqueId()) && e.getTarget() instanceof SubServer && !((SubServer) e.getTarget()).isRunning()) { + } else if (e.getPlayer().getServer() != null && !fallback.containsKey(e.getPlayer().getUniqueId()) && e.getTarget() instanceof SubServer && !((SubServer) e.getTarget()).isRunning()) { e.getPlayer().sendMessage(api.getLang("SubServers", "Bungee.Server.Offline")); e.setCancelled(true); } - if (fallbackLimbo.keySet().contains(e.getPlayer().getUniqueId())) { - if (fallbackLimbo.get(e.getPlayer().getUniqueId()).contains(e.getTarget())) { - fallbackLimbo.get(e.getPlayer().getUniqueId()).remove(e.getTarget()); + if (fallback.containsKey(e.getPlayer().getUniqueId())) { + FallbackState state = fallback.get(e.getPlayer().getUniqueId()); + if (state.names.contains(e.getTarget().getName())) { + state.remove(e.getTarget().getName()); } else if (e.getPlayer().getServer() != null) { - e.setCancelled(true); + fallback.remove(e.getPlayer().getUniqueId()); } } } else { @@ -992,18 +994,13 @@ public final class SubProxy extends BungeeCommon implements Listener { } - if (fallbackLimbo.keySet().contains(e.getPlayer().getUniqueId())) { - Timer timer = new Timer("SubServers.Bungee::Fallback_Limbo_Timer(" + e.getPlayer().getUniqueId() + ')'); - timer.schedule(new TimerTask() { - @Override - public void run() { - if (e.getPlayer().getServer() != null && !((UserConnection) e.getPlayer()).isDimensionChange() && e.getPlayer().getServer().getInfo().getAddress().equals(e.getServer().getInfo().getAddress())) { - fallbackLimbo.remove(e.getPlayer().getUniqueId()); - e.getPlayer().sendMessage(api.getLang("SubServers", "Bungee.Feature.Smart-Fallback.Result").replace("$str$", (e.getServer().getInfo() instanceof Server)?((Server) e.getServer().getInfo()).getDisplayName():e.getServer().getInfo().getName())); - } - timer.cancel(); + if (fallback.containsKey(e.getPlayer().getUniqueId())) { + fallback.get(e.getPlayer().getUniqueId()).done(() -> { + if (e.getPlayer().getServer() != null && !((UserConnection) e.getPlayer()).isDimensionChange() && e.getPlayer().getServer().getInfo().getName().equals(e.getServer().getInfo().getName())) { + fallback.remove(e.getPlayer().getUniqueId()); + e.getPlayer().sendMessage(api.getLang("SubServers", "Bungee.Feature.Smart-Fallback.Result").replace("$str$", (e.getServer().getInfo() instanceof Server)?((Server) e.getServer().getInfo()).getDisplayName():e.getServer().getInfo().getName())); } - }, 1000); + }, getConfig().getServerConnectTimeout() + 500); } } } @@ -1012,25 +1009,28 @@ public final class SubProxy extends BungeeCommon implements Listener { @EventHandler(priority = Byte.MAX_VALUE) public void fallback(ServerKickEvent e) { if (e.getPlayer().isConnected() && e.getPlayer() instanceof UserConnection && config.get().getMap("Settings").getMap("Smart-Fallback", new ObjectMap<>()).getBoolean("Fallback", true)) { - Map fallbacks; - if (!fallbackLimbo.keySet().contains(e.getPlayer().getUniqueId())) { - fallbacks = SmartFallback.getFallbackServers(e.getPlayer().getPendingConnection().getListener(), e.getPlayer()); + FallbackState state; + boolean init = !fallback.containsKey(e.getPlayer().getUniqueId()); + if (init) { + Map map = SmartFallback.getFallbackServers(e.getPlayer().getPendingConnection().getListener(), e.getPlayer()); + map.remove(e.getKickedFrom().getName()); + state = new FallbackState(e.getPlayer().getUniqueId(), map, e.getKickReasonComponent()); } else { - fallbacks = new LinkedHashMap(); - for (ServerInfo server : fallbackLimbo.get(e.getPlayer().getUniqueId())) fallbacks.put(server.getName(), server); + state = fallback.get(e.getPlayer().getUniqueId()); + e.setKickReasonComponent(state.reason); + LinkedList tmp = new LinkedList<>(state.servers); + for (ServerInfo server : tmp) if (server.getName().equals(e.getKickedFrom().getName())) + state.remove(server); } - fallbacks.remove(e.getKickedFrom().getName()); - if (!fallbacks.isEmpty()) { + if (!state.servers.isEmpty()) { e.setCancelled(true); e.getPlayer().sendMessage(api.getLang("SubServers", "Bungee.Feature.Smart-Fallback").replace("$str$", (e.getKickedFrom() instanceof Server)?((Server) e.getKickedFrom()).getDisplayName():e.getKickedFrom().getName()).replace("$msg$", e.getKickReason())); - if (!fallbackLimbo.keySet().contains(e.getPlayer().getUniqueId())) fallbackLimbo.put(e.getPlayer().getUniqueId(), new LinkedList<>(fallbacks.values())); + if (init) fallback.put(e.getPlayer().getUniqueId(), state); - ServerInfo next = new LinkedList>(fallbacks.entrySet()).getFirst().getValue(); - e.setCancelServer(next); - if (Util.isException(() -> Util.reflect(ServerKickEvent.class.getDeclaredMethod("setCancelServers", ServerInfo[].class), e, (Object) fallbacks.values().toArray(new ServerInfo[0])))) { - ((UserConnection) e.getPlayer()).setServerJoinQueue(new LinkedList<>(fallbacks.keySet())); - ((UserConnection) e.getPlayer()).connect(next, null, true); + e.setCancelServer(state.servers.getFirst()); + if (Util.isException(() -> Util.reflect(ServerKickEvent.class.getDeclaredMethod("setCancelServers", ServerInfo[].class), e, (Object) state.servers.toArray(new ServerInfo[0])))) { + ((UserConnection) e.getPlayer()).setServerJoinQueue(new LinkedList<>(state.names)); } } } @@ -1039,7 +1039,7 @@ public final class SubProxy extends BungeeCommon implements Listener { @EventHandler(priority = Byte.MAX_VALUE) public void disconnected(PlayerDisconnectEvent e) { UUID id = e.getPlayer().getUniqueId(); - fallbackLimbo.remove(id); + fallback.remove(id); SubCommand.players.remove(id); synchronized (rPlayers) { diff --git a/SubServers.Creator/Spigot/template.yml b/SubServers.Creator/Spigot/template.yml index 6664802e..7f23b319 100644 --- a/SubServers.Creator/Spigot/template.yml +++ b/SubServers.Creator/Spigot/template.yml @@ -8,4 +8,4 @@ Template: Can-Update: true Executable: 'bash build.sh' Settings: - Executable: 'java -Xmx1024M -Dorg.bukkit.craftbukkit.libs.jline.terminal=unix -Djansi.passthrough=true -jar Spigot.jar nogui' \ No newline at end of file + Executable: 'java -Xmx1024M -Dorg.bukkit.craftbukkit.libs.jline.terminal=none -Djansi.passthrough=true -jar Spigot.jar nogui' \ No newline at end of file diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/ExProxy.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/ExProxy.java index b375f178..e66a0b95 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/ExProxy.java +++ b/SubServers.Sync/src/net/ME1312/SubServers/Sync/ExProxy.java @@ -17,6 +17,7 @@ import net.ME1312.SubData.Client.SubDataClient; import net.ME1312.SubServers.Bungee.BungeeCommon; import net.ME1312.SubServers.Bungee.Library.Compatibility.Galaxi.GalaxiCommand; import net.ME1312.SubServers.Bungee.Library.Compatibility.Logger; +import net.ME1312.SubServers.Bungee.Library.Fallback.FallbackState; import net.ME1312.SubServers.Bungee.Library.Fallback.SmartFallback; import net.ME1312.SubServers.Sync.Event.*; import net.ME1312.SubServers.Sync.Library.Compatibility.Plugin; @@ -62,7 +63,7 @@ public final class ExProxy extends BungeeCommon implements Listener { public final HashMap rPlayerLinkS = new HashMap(); public final HashMap rPlayerLinkP = new HashMap(); public final HashMap rPlayers = new HashMap(); - private final HashMap> fallbackLimbo = new HashMap>(); + private final HashMap fallback = new HashMap(); public final PrintStream out; public final UniversalFile dir = new UniversalFile(new File(System.getProperty("user.dir"))); @@ -478,8 +479,8 @@ public final class ExProxy extends BungeeCommon implements Listener { } if (!e.getTarget().canAccess(e.getPlayer())) { - if (e.getPlayer().getServer() == null || fallbackLimbo.keySet().contains(e.getPlayer().getUniqueId())) { - if (!fallbackLimbo.keySet().contains(e.getPlayer().getUniqueId()) || fallbackLimbo.get(e.getPlayer().getUniqueId()).contains(e.getTarget())) { + if (e.getPlayer().getServer() == null || fallback.containsKey(e.getPlayer().getUniqueId())) { + if (!fallback.containsKey(e.getPlayer().getUniqueId()) || fallback.get(e.getPlayer().getUniqueId()).names.contains(e.getTarget().getName())) { ServerKickEvent kick = new ServerKickEvent(e.getPlayer(), e.getTarget(), new BaseComponent[]{ new TextComponent(getTranslation("no_server_permission")) }, null, ServerKickEvent.State.CONNECTING); @@ -491,16 +492,17 @@ public final class ExProxy extends BungeeCommon implements Listener { e.getPlayer().sendMessage(getTranslation("no_server_permission")); e.setCancelled(true); } - } else if (e.getPlayer().getServer() != null && !fallbackLimbo.keySet().contains(e.getPlayer().getUniqueId()) && e.getTarget() instanceof SubServerImpl && !((SubServerImpl) e.getTarget()).isRunning()) { + } else if (e.getPlayer().getServer() != null && !fallback.containsKey(e.getPlayer().getUniqueId()) && e.getTarget() instanceof SubServerImpl && !((SubServerImpl) e.getTarget()).isRunning()) { e.getPlayer().sendMessage(api.getLang("SubServers", "Bungee.Server.Offline")); e.setCancelled(true); } - if (fallbackLimbo.keySet().contains(e.getPlayer().getUniqueId())) { - if (fallbackLimbo.get(e.getPlayer().getUniqueId()).contains(e.getTarget())) { - fallbackLimbo.get(e.getPlayer().getUniqueId()).remove(e.getTarget()); + if (fallback.containsKey(e.getPlayer().getUniqueId())) { + FallbackState state = fallback.get(e.getPlayer().getUniqueId()); + if (state.names.contains(e.getTarget().getName())) { + state.remove(e.getTarget().getName()); } else if (e.getPlayer().getServer() != null) { - e.setCancelled(true); + fallback.remove(e.getPlayer().getUniqueId()); } } } else { @@ -525,18 +527,13 @@ public final class ExProxy extends BungeeCommon implements Listener { } - if (fallbackLimbo.keySet().contains(e.getPlayer().getUniqueId())) { - Timer timer = new Timer("SubServers.Sync::Fallback_Limbo_Timer(" + e.getPlayer().getUniqueId() + ')'); - timer.schedule(new TimerTask() { - @Override - public void run() { - if (e.getPlayer().getServer() != null && !((UserConnection) e.getPlayer()).isDimensionChange() && e.getPlayer().getServer().getInfo().getAddress().equals(e.getServer().getInfo().getAddress())) { - fallbackLimbo.remove(e.getPlayer().getUniqueId()); - e.getPlayer().sendMessage(api.getLang("SubServers", "Bungee.Feature.Smart-Fallback.Result").replace("$str$", (e.getServer().getInfo() instanceof ServerImpl)?((ServerImpl) e.getServer().getInfo()).getDisplayName():e.getServer().getInfo().getName())); - } - timer.cancel(); + if (fallback.containsKey(e.getPlayer().getUniqueId())) { + fallback.get(e.getPlayer().getUniqueId()).done(() -> { + if (e.getPlayer().getServer() != null && !((UserConnection) e.getPlayer()).isDimensionChange() && e.getPlayer().getServer().getInfo().getName().equals(e.getServer().getInfo().getName())) { + fallback.remove(e.getPlayer().getUniqueId()); + e.getPlayer().sendMessage(api.getLang("SubServers", "Bungee.Feature.Smart-Fallback.Result").replace("$str$", (e.getServer().getInfo() instanceof ServerImpl)?((ServerImpl) e.getServer().getInfo()).getDisplayName():e.getServer().getInfo().getName())); } - }, 1000); + }, getConfig().getServerConnectTimeout() + 500); } } } @@ -545,25 +542,28 @@ public final class ExProxy extends BungeeCommon implements Listener { @EventHandler(priority = Byte.MAX_VALUE) public void fallback(ServerKickEvent e) { if (e.getPlayer().isConnected() && e.getPlayer() instanceof UserConnection && config.get().getMap("Settings").getMap("Smart-Fallback", new ObjectMap<>()).getBoolean("Fallback", true)) { - Map fallbacks; - if (!fallbackLimbo.keySet().contains(e.getPlayer().getUniqueId())) { - fallbacks = SmartFallback.getFallbackServers(e.getPlayer().getPendingConnection().getListener(), e.getPlayer()); + FallbackState state; + boolean init = !fallback.containsKey(e.getPlayer().getUniqueId()); + if (init) { + Map map = SmartFallback.getFallbackServers(e.getPlayer().getPendingConnection().getListener(), e.getPlayer()); + map.remove(e.getKickedFrom().getName()); + state = new FallbackState(e.getPlayer().getUniqueId(), map, e.getKickReasonComponent()); } else { - fallbacks = new LinkedHashMap(); - for (ServerInfo server : fallbackLimbo.get(e.getPlayer().getUniqueId())) fallbacks.put(server.getName(), server); + state = fallback.get(e.getPlayer().getUniqueId()); + e.setKickReasonComponent(state.reason); + LinkedList tmp = new LinkedList<>(state.servers); + for (ServerInfo server : tmp) if (server.getName().equals(e.getKickedFrom().getName())) + state.remove(server); } - fallbacks.remove(e.getKickedFrom().getName()); - if (!fallbacks.isEmpty()) { + if (!state.servers.isEmpty()) { e.setCancelled(true); e.getPlayer().sendMessage(api.getLang("SubServers", "Bungee.Feature.Smart-Fallback").replace("$str$", (e.getKickedFrom() instanceof ServerImpl)?((ServerImpl) e.getKickedFrom()).getDisplayName():e.getKickedFrom().getName()).replace("$msg$", e.getKickReason())); - if (!fallbackLimbo.keySet().contains(e.getPlayer().getUniqueId())) fallbackLimbo.put(e.getPlayer().getUniqueId(), new LinkedList<>(fallbacks.values())); + if (init) fallback.put(e.getPlayer().getUniqueId(), state); - ServerInfo next = new LinkedList>(fallbacks.entrySet()).getFirst().getValue(); - e.setCancelServer(next); - if (Util.isException(() -> Util.reflect(ServerKickEvent.class.getDeclaredMethod("setCancelServers", ServerInfo[].class), e, (Object) fallbacks.values().toArray(new ServerInfo[0])))) { - ((UserConnection) e.getPlayer()).setServerJoinQueue(new LinkedList<>(fallbacks.keySet())); - ((UserConnection) e.getPlayer()).connect(next, null, true); + e.setCancelServer(state.servers.getFirst()); + if (Util.isException(() -> Util.reflect(ServerKickEvent.class.getDeclaredMethod("setCancelServers", ServerInfo[].class), e, (Object) state.servers.toArray(new ServerInfo[0])))) { + ((UserConnection) e.getPlayer()).setServerJoinQueue(new LinkedList<>(state.names)); } } } @@ -572,7 +572,7 @@ public final class ExProxy extends BungeeCommon implements Listener { @EventHandler(priority = Byte.MAX_VALUE) public void disconnected(PlayerDisconnectEvent e) { UUID id = e.getPlayer().getUniqueId(); - fallbackLimbo.remove(id); + fallback.remove(id); SubCommand.permitted.remove(id); synchronized (rPlayers) {