From 57fd78eac567901f46947b7f1744f4812ebd04bf Mon Sep 17 00:00:00 2001 From: filoghost Date: Fri, 19 Mar 2021 19:48:13 +0100 Subject: [PATCH] Refactor BungeeCord-related code --- .../HolographicDisplays.java | 8 +- .../bridge/bungeecord/BungeeChannel.java | 97 ------- .../bridge/bungeecord/BungeeMessenger.java | 103 +++++++ .../bridge/bungeecord/BungeeServerInfo.java | 88 ------ .../bungeecord/BungeeServerTracker.java | 253 +++++++----------- .../bridge/bungeecord/ServerInfo.java | 70 +++++ .../bungeecord/pinger/PingResponse.java | 101 +++++++ .../bungeecord/pinger/ServerPinger.java | 96 +++++++ .../bungeecord/serverpinger/PacketUtils.java | 57 ---- .../bungeecord/serverpinger/PingResponse.java | 89 ------ .../bungeecord/serverpinger/ServerPinger.java | 55 ---- .../disk/Configuration.java | 12 +- .../placeholder/PlaceholdersManager.java | 50 ++-- .../task/BungeeCleanupTask.java | 46 ---- 14 files changed, 508 insertions(+), 617 deletions(-) delete mode 100644 plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/BungeeChannel.java create mode 100644 plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/BungeeMessenger.java delete mode 100644 plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/BungeeServerInfo.java create mode 100644 plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/ServerInfo.java create mode 100644 plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/pinger/PingResponse.java create mode 100644 plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/pinger/ServerPinger.java delete mode 100644 plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/PacketUtils.java delete mode 100644 plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/PingResponse.java delete mode 100644 plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerPinger.java delete mode 100644 plugin/src/main/java/me/filoghost/holographicdisplays/task/BungeeCleanupTask.java diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/HolographicDisplays.java b/plugin/src/main/java/me/filoghost/holographicdisplays/HolographicDisplays.java index 06213032..1c489de8 100644 --- a/plugin/src/main/java/me/filoghost/holographicdisplays/HolographicDisplays.java +++ b/plugin/src/main/java/me/filoghost/holographicdisplays/HolographicDisplays.java @@ -30,7 +30,6 @@ import me.filoghost.holographicdisplays.object.internal.InternalHologram; import me.filoghost.holographicdisplays.object.internal.InternalHologramManager; import me.filoghost.holographicdisplays.placeholder.AnimationsRegistry; import me.filoghost.holographicdisplays.placeholder.PlaceholdersManager; -import me.filoghost.holographicdisplays.task.BungeeCleanupTask; import me.filoghost.holographicdisplays.task.WorldPlayerCounterTask; import me.filoghost.holographicdisplays.util.NMSVersion; import org.bstats.bukkit.MetricsLite; @@ -38,6 +37,7 @@ import org.bukkit.Bukkit; import org.bukkit.ChatColor; import java.io.IOException; +import java.util.concurrent.TimeUnit; public class HolographicDisplays extends FCommonsPlugin implements ProtocolPacketSettings { @@ -112,7 +112,6 @@ public class HolographicDisplays extends FCommonsPlugin implements ProtocolPacke // Start repeating tasks. placeholderManager.startRefreshTask(this); - Bukkit.getScheduler().scheduleSyncRepeatingTask(this, new BungeeCleanupTask(bungeeServerTracker), 5 * 60 * 20, 5 * 60 * 20); Bukkit.getScheduler().scheduleSyncRepeatingTask(this, new WorldPlayerCounterTask(), 0L, 3 * 20); HologramCommandManager commandManager = new HologramCommandManager(configManager, internalHologramManager, nmsManager); @@ -142,8 +141,7 @@ public class HolographicDisplays extends FCommonsPlugin implements ProtocolPacke public void load(boolean deferHologramsCreation, ErrorCollector errorCollector) { placeholderManager.untrackAll(); internalHologramManager.clearAll(); - bungeeServerTracker.resetTrackedServers(); - + configManager.reloadCustomPlaceholders(errorCollector); configManager.reloadMainConfig(errorCollector); HologramDatabase hologramDatabase = configManager.loadHologramDatabase(errorCollector); @@ -153,7 +151,7 @@ public class HolographicDisplays extends FCommonsPlugin implements ProtocolPacke errorCollector.add(e, "failed to load animation files"); } - bungeeServerTracker.restartTask(Configuration.bungeeRefreshSeconds); + bungeeServerTracker.restart(Configuration.bungeeRefreshSeconds, TimeUnit.SECONDS); if (deferHologramsCreation) { // For the initial load: holograms are loaded later, when the worlds are ready diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/BungeeChannel.java b/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/BungeeChannel.java deleted file mode 100644 index 3f3172bc..00000000 --- a/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/BungeeChannel.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) filoghost and contributors - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ -package me.filoghost.holographicdisplays.bridge.bungeecord; - -import me.filoghost.fcommons.logging.Log; -import me.filoghost.holographicdisplays.HolographicDisplays; -import me.filoghost.holographicdisplays.disk.Configuration; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.messaging.PluginMessageListener; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.EOFException; -import java.io.IOException; -import java.util.Collection; - -public class BungeeChannel implements PluginMessageListener { - - private static final String BUNGEECORD_CHANNEL = "BungeeCord"; - private static final String REDISBUNGEE_CHANNEL = "legacy:redisbungee"; - - private final BungeeServerTracker bungeeServerTracker; - - public BungeeChannel(BungeeServerTracker bungeeServerTracker) { - this.bungeeServerTracker = bungeeServerTracker; - } - - public void register(Plugin plugin) { - Bukkit.getMessenger().registerOutgoingPluginChannel(plugin, BUNGEECORD_CHANNEL); - Bukkit.getMessenger().registerIncomingPluginChannel(plugin, BUNGEECORD_CHANNEL, this); - - Bukkit.getMessenger().registerOutgoingPluginChannel(plugin, REDISBUNGEE_CHANNEL); - Bukkit.getMessenger().registerIncomingPluginChannel(plugin, REDISBUNGEE_CHANNEL, this); - } - - private String getTargetChannel() { - if (Configuration.useRedisBungee) { - return REDISBUNGEE_CHANNEL; - } else { - return BUNGEECORD_CHANNEL; - } - } - - @Override - public void onPluginMessageReceived(String channel, Player player, byte[] message) { - if (channel.equals(getTargetChannel())) { - DataInputStream in = new DataInputStream(new ByteArrayInputStream(message)); - - try { - String subChannel = in.readUTF(); - - if (subChannel.equals("PlayerCount")) { - String server = in.readUTF(); - - if (in.available() > 0) { - int online = in.readInt(); - - BungeeServerInfo serverInfo = bungeeServerTracker.getOrCreateServerInfo(server); - serverInfo.setOnlinePlayers(online); - } - } - - } catch (EOFException e) { - // Do nothing. - } catch (IOException e) { - // This should never happen. - e.printStackTrace(); - } - } - } - - public void askPlayerCount(String server) { - ByteArrayOutputStream b = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(b); - - try { - out.writeUTF("PlayerCount"); - out.writeUTF(server); - } catch (IOException e) { - // It should not happen. - Log.warning("I/O Exception while asking for player count on server '" + server + "'.", e); - } - - // OR, if you don't need to send it to a specific player - Collection players = Bukkit.getOnlinePlayers(); - if (players.size() > 0) { - players.iterator().next().sendPluginMessage(HolographicDisplays.getInstance(), getTargetChannel(), b.toByteArray()); - } - } -} diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/BungeeMessenger.java b/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/BungeeMessenger.java new file mode 100644 index 00000000..1d9d9bfd --- /dev/null +++ b/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/BungeeMessenger.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) filoghost and contributors + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package me.filoghost.holographicdisplays.bridge.bungeecord; + +import me.filoghost.fcommons.logging.Log; +import me.filoghost.holographicdisplays.disk.Configuration; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.messaging.PluginMessageListener; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Collection; + +public class BungeeMessenger implements PluginMessageListener { + + private static final String BUNGEECORD_CHANNEL = "BungeeCord"; + private static final String REDISBUNGEE_CHANNEL = "legacy:redisbungee"; + + private final Plugin plugin; + private final PlayerCountCallback playerCountCallback; + + private BungeeMessenger(Plugin plugin, PlayerCountCallback playerCountCallback) { + this.plugin = plugin; + this.playerCountCallback = playerCountCallback; + } + + public static BungeeMessenger registerNew(Plugin plugin, PlayerCountCallback playerCountCallback) { + BungeeMessenger bungeeMessenger = new BungeeMessenger(plugin, playerCountCallback); + + Bukkit.getMessenger().registerOutgoingPluginChannel(plugin, BUNGEECORD_CHANNEL); + Bukkit.getMessenger().registerIncomingPluginChannel(plugin, BUNGEECORD_CHANNEL, bungeeMessenger); + + Bukkit.getMessenger().registerOutgoingPluginChannel(plugin, REDISBUNGEE_CHANNEL); + Bukkit.getMessenger().registerIncomingPluginChannel(plugin, REDISBUNGEE_CHANNEL, bungeeMessenger); + + return bungeeMessenger; + } + + @Override + public void onPluginMessageReceived(String channel, Player player, byte[] message) { + if (Configuration.pingerEnabled || !channel.equals(getTargetChannel())) { + return; + } + + DataInputStream in = new DataInputStream(new ByteArrayInputStream(message)); + + try { + String subChannel = in.readUTF(); + if (!subChannel.equals("PlayerCount")) { + return; + } + + String server = in.readUTF(); + int online = in.readInt(); + playerCountCallback.onReceive(server, online); + } catch (IOException e) { + Log.warning("Error while decoding player count from BungeeCord.", e); + } + } + + public void sendPlayerCountRequest(String server) { + ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(byteOut); + + try { + out.writeUTF("PlayerCount"); + out.writeUTF(server); + } catch (IOException e) { + Log.warning("Error while encoding player count message for server \"" + server + "\".", e); + } + + // Send the message through a random player (BungeeCord will not forward it to them) + Collection players = Bukkit.getOnlinePlayers(); + if (players.size() > 0) { + Player player = players.iterator().next(); + player.sendPluginMessage(plugin, getTargetChannel(), byteOut.toByteArray()); + } + } + + private String getTargetChannel() { + if (Configuration.useRedisBungee) { + return REDISBUNGEE_CHANNEL; + } else { + return BUNGEECORD_CHANNEL; + } + } + + + public interface PlayerCountCallback { + + void onReceive(String serverName, int playerCount); + + } + +} diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/BungeeServerInfo.java b/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/BungeeServerInfo.java deleted file mode 100644 index 0bd88b33..00000000 --- a/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/BungeeServerInfo.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) filoghost and contributors - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ -package me.filoghost.holographicdisplays.bridge.bungeecord; - -import me.filoghost.holographicdisplays.disk.Configuration; - -public class BungeeServerInfo { - - private volatile boolean isOnline; - private volatile int onlinePlayers; - private volatile int maxPlayers; - - // The two lines of a motd - private volatile String motd1; // Should never be null - private volatile String motd2; // Should never be null - - private volatile long lastRequest; - - protected BungeeServerInfo() { - isOnline = false; - this.motd1 = ""; - this.motd2 = ""; - updateLastRequest(); - } - - public boolean isOnline() { - return isOnline; - } - - public void setOnline(boolean isOnline) { - this.isOnline = isOnline; - } - - public int getOnlinePlayers() { - return onlinePlayers; - } - - public void setOnlinePlayers(int onlinePlayers) { - this.onlinePlayers = onlinePlayers; - } - - public int getMaxPlayers() { - return maxPlayers; - } - - public void setMaxPlayers(int maxPlayers) { - this.maxPlayers = maxPlayers; - } - - public String getMotd1() { - return motd1; - } - - public String getMotd2() { - return motd2; - } - - public void setMotd(String motd) { - if (motd == null) { - this.motd1 = ""; - this.motd2 = ""; - return; - } - - int separatorIndex = motd.indexOf("\n"); - if (separatorIndex >= 0) { - String line1 = motd.substring(0, separatorIndex); - String line2 = motd.substring(separatorIndex + 1); - this.motd1 = Configuration.pingerTrimMotd ? line1.trim() : line1; - this.motd2 = Configuration.pingerTrimMotd ? line2.trim() : line2; - } else { - this.motd1 = Configuration.pingerTrimMotd ? motd.trim() : motd; - this.motd2 = ""; - } - } - - public long getLastRequest() { - return lastRequest; - } - - public void updateLastRequest() { - this.lastRequest = System.currentTimeMillis(); - } - -} diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/BungeeServerTracker.java b/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/BungeeServerTracker.java index 767db7c4..0c41a981 100644 --- a/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/BungeeServerTracker.java +++ b/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/BungeeServerTracker.java @@ -7,8 +7,9 @@ package me.filoghost.holographicdisplays.bridge.bungeecord; import me.filoghost.fcommons.logging.Log; import me.filoghost.holographicdisplays.HolographicDisplays; -import me.filoghost.holographicdisplays.bridge.bungeecord.serverpinger.PingResponse; -import me.filoghost.holographicdisplays.bridge.bungeecord.serverpinger.ServerPinger; +import me.filoghost.holographicdisplays.bridge.bungeecord.pinger.PingResponse; +import me.filoghost.holographicdisplays.bridge.bungeecord.pinger.ServerPinger; +import me.filoghost.holographicdisplays.core.DebugLogger; import me.filoghost.holographicdisplays.disk.Configuration; import me.filoghost.holographicdisplays.disk.ServerAddress; import org.bukkit.Bukkit; @@ -17,184 +18,122 @@ import org.bukkit.plugin.Plugin; import java.io.IOException; import java.net.SocketTimeoutException; import java.net.UnknownHostException; -import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; public class BungeeServerTracker { - private static final String PINGER_NOT_ENABLED_ERROR = "[Please enable pinger]"; + private static final long UNTRACK_AFTER_TIME_WITHOUT_REQUESTS = TimeUnit.MINUTES.toMillis(10); - private final BungeeChannel bungeeChannel; - private final Map trackedServers; + private final ConcurrentMap trackedServers; + private final BungeeMessenger bungeeMessenger; private int taskID = -1; public BungeeServerTracker(Plugin plugin) { - bungeeChannel = new BungeeChannel(this); - bungeeChannel.register(plugin); trackedServers = new ConcurrentHashMap<>(); + bungeeMessenger = BungeeMessenger.registerNew(plugin, this::updateServerInfoFromBungee); } - public void resetTrackedServers() { + public void restart(int updateInterval, TimeUnit timeUnit) { trackedServers.clear(); - } - - public void track(String server) { - if (!trackedServers.containsKey(server)) { - BungeeServerInfo info = new BungeeServerInfo(); - info.setMotd(Configuration.pingerOfflineMotd); - trackedServers.put(server, info); - - if (!Configuration.pingerEnabled) { - bungeeChannel.askPlayerCount(server); - } - } - } - - protected BungeeServerInfo getOrCreateServerInfo(String server) { - BungeeServerInfo info = trackedServers.get(server); - if (info == null) { - info = new BungeeServerInfo(); - info.setMotd(Configuration.pingerOfflineMotd); - trackedServers.put(server, info); - } - return info; - } - - public int getPlayersOnline(String server) { - BungeeServerInfo info = trackedServers.get(server); - if (info != null) { - info.updateLastRequest(); - return info.getOnlinePlayers(); - } else { - // It was not tracked, add it. - track(server); - return 0; - } - } - - public String getMaxPlayers(String server) { - if (!Configuration.pingerEnabled) { - return PINGER_NOT_ENABLED_ERROR; - } - - BungeeServerInfo info = trackedServers.get(server); - if (info != null) { - info.updateLastRequest(); - return String.valueOf(info.getMaxPlayers()); - } else { - // It was not tracked, add it. - track(server); - return "0"; - } - } - - public String getMotd1(String server) { - if (!Configuration.pingerEnabled) { - return PINGER_NOT_ENABLED_ERROR; - } - - BungeeServerInfo info = trackedServers.get(server); - if (info != null) { - info.updateLastRequest(); - return info.getMotd1(); - } else { - // It was not tracked, add it. - track(server); - return Configuration.pingerOfflineMotd; - } - } - - public String getMotd2(String server) { - if (!Configuration.pingerEnabled) { - return PINGER_NOT_ENABLED_ERROR; - } - - BungeeServerInfo info = trackedServers.get(server); - if (info != null) { - info.updateLastRequest(); - return info.getMotd2(); - } else { - // It was not tracked, add it. - track(server); - return ""; - } - } - - public String getOnlineStatus(String server) { - if (!Configuration.pingerEnabled) { - return PINGER_NOT_ENABLED_ERROR; - } - - BungeeServerInfo info = trackedServers.get(server); - if (info != null) { - info.updateLastRequest(); - return info.isOnline() ? Configuration.pingerStatusOnline : Configuration.pingerStatusOffline; - } else { - // It was not tracked, add it. - track(server); - return Configuration.pingerStatusOffline; - } - } - - public Map getTrackedServers() { - return trackedServers; - } - - public void restartTask(int refreshSeconds) { if (taskID != -1) { Bukkit.getScheduler().cancelTask(taskID); } - - taskID = Bukkit.getScheduler().scheduleSyncRepeatingTask(HolographicDisplays.getInstance(), () -> { - if (Configuration.pingerEnabled) { - runAsyncPinger(); - } else { - for (String server : trackedServers.keySet()) { - bungeeChannel.askPlayerCount(server); - } - } - }, 1, refreshSeconds * 20L); + taskID = Bukkit.getScheduler().scheduleSyncRepeatingTask(HolographicDisplays.getInstance(), + this::runPeriodicUpdateTask, 1, timeUnit.toSeconds(updateInterval) * 20L); } - private void runAsyncPinger() { - Bukkit.getScheduler().runTaskAsynchronously(HolographicDisplays.getInstance(), () -> { - for (ServerAddress serverAddress : Configuration.pingerServers) { - BungeeServerInfo serverInfo = getOrCreateServerInfo(serverAddress.getName()); - boolean displayOffline = false; - - try { - PingResponse data = ServerPinger.fetchData(serverAddress, Configuration.pingerTimeout); - - if (data.isOnline()) { - serverInfo.setOnline(true); - serverInfo.setOnlinePlayers(data.getOnlinePlayers()); - serverInfo.setMaxPlayers(data.getMaxPlayers()); - serverInfo.setMotd(data.getMotd()); - } else { - displayOffline = true; - } - } catch (SocketTimeoutException e) { - // Common error, avoid logging - displayOffline = true; - } catch (UnknownHostException e) { - Log.warning("Couldn't fetch data from " + serverAddress + ": unknown host address."); - displayOffline = true; - } catch (IOException e) { - Log.warning("Couldn't fetch data from " + serverAddress + ".", e); - displayOffline = true; - } - - if (displayOffline) { - serverInfo.setOnline(false); - serverInfo.setOnlinePlayers(0); - serverInfo.setMaxPlayers(0); - serverInfo.setMotd(Configuration.pingerOfflineMotd); + public ServerInfo getCurrentServerInfo(String serverName) { + // If it wasn't already tracked, send an update request instantly + if (!Configuration.pingerEnabled && !trackedServers.containsKey(serverName)) { + bungeeMessenger.sendPlayerCountRequest(serverName); + } + + TrackedServer trackedServer = trackedServers.computeIfAbsent(serverName, TrackedServer::new); + trackedServer.updateLastRequest(); + return trackedServer.serverInfo; + } + + private void runPeriodicUpdateTask() { + removeUnusedServers(); + + if (Configuration.pingerEnabled) { + Bukkit.getScheduler().runTaskAsynchronously(HolographicDisplays.getInstance(), () -> { + for (TrackedServer trackedServer : trackedServers.values()) { + updateServerInfoWithPinger(trackedServer); } + }); + } else { + for (String serverName : trackedServers.keySet()) { + bungeeMessenger.sendPlayerCountRequest(serverName); + } + } + } + + private void updateServerInfoWithPinger(TrackedServer trackedServer) { + ServerAddress serverAddress = Configuration.pingerServerAddresses.get(trackedServer.serverName); + + if (serverAddress != null) { + trackedServer.serverInfo = pingServer(serverAddress); + } else { + trackedServer.serverInfo = ServerInfo.offline("[Unknown server: " + trackedServer.serverName + "]"); + } + } + + private void updateServerInfoFromBungee(String serverName, int onlinePlayers) { + TrackedServer trackedServer = trackedServers.get(serverName); + if (trackedServer != null) { + trackedServer.serverInfo = ServerInfo.online(onlinePlayers, 0, ""); + } + } + + private ServerInfo pingServer(ServerAddress serverAddress) { + try { + PingResponse data = ServerPinger.fetchData(serverAddress, Configuration.pingerTimeout); + return ServerInfo.online(data.getOnlinePlayers(), data.getMaxPlayers(), data.getMotd()); + } catch (SocketTimeoutException e) { + // Common error, do not log + } catch (UnknownHostException e) { + Log.warning("Couldn't fetch data from " + serverAddress + ": unknown host address."); + } catch (IOException e) { + Log.warning("Couldn't fetch data from " + serverAddress + ".", e); + } + + return ServerInfo.offline(Configuration.pingerOfflineMotd); + } + + private void removeUnusedServers() { + long now = System.currentTimeMillis(); + + trackedServers.values().removeIf(trackedServer -> { + if (now - trackedServer.lastRequest > UNTRACK_AFTER_TIME_WITHOUT_REQUESTS) { + DebugLogger.info("Untracked unused server \"" + trackedServer.serverName + "\"."); + return true; + } else { + return false; } }); } + private static class TrackedServer { + + private final String serverName; + private volatile ServerInfo serverInfo; + private volatile long lastRequest; + + private TrackedServer(String serverName) { + this.serverName = serverName; + this.serverInfo = ServerInfo.offline(Configuration.pingerOfflineMotd); + } + + private void updateLastRequest() { + this.lastRequest = System.currentTimeMillis(); + } + + } + } diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/ServerInfo.java b/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/ServerInfo.java new file mode 100644 index 00000000..9a0a39d3 --- /dev/null +++ b/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/ServerInfo.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) filoghost and contributors + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package me.filoghost.holographicdisplays.bridge.bungeecord; + +import me.filoghost.fcommons.Strings; +import me.filoghost.holographicdisplays.disk.Configuration; + +public class ServerInfo { + + private final boolean online; + private final int onlinePlayers; + private final int maxPlayers; + private final String motdLine1, motdLine2; + + public static ServerInfo online(int onlinePlayers, int maxPlayers, String motd) { + return new ServerInfo(true, onlinePlayers, maxPlayers, motd); + } + + public static ServerInfo offline(String motd) { + return new ServerInfo(false, 0, 0, motd); + } + + private ServerInfo(boolean online, int onlinePlayers, int maxPlayers, String motd) { + this.online = online; + this.onlinePlayers = onlinePlayers; + this.maxPlayers = maxPlayers; + + if (Strings.isEmpty(motd)) { + motdLine1 = ""; + motdLine2 = ""; + } else if (motd.contains("\n")) { + String[] lines = Strings.split(motd, "\n", 2); + if (Configuration.pingerTrimMotd) { + lines = Strings.trim(lines); + } + motdLine1 = lines[0]; + motdLine2 = lines.length > 1 ? lines[1] : ""; + } else { + if (Configuration.pingerTrimMotd) { + motd = motd.trim(); + } + motdLine1 = motd; + motdLine2 = ""; + } + } + + public boolean isOnline() { + return online; + } + + public int getOnlinePlayers() { + return onlinePlayers; + } + + public int getMaxPlayers() { + return maxPlayers; + } + + public String getMotdLine1() { + return motdLine1; + } + + public String getMotdLine2() { + return motdLine2; + } + +} diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/pinger/PingResponse.java b/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/pinger/PingResponse.java new file mode 100644 index 00000000..409890cf --- /dev/null +++ b/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/pinger/PingResponse.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) filoghost and contributors + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package me.filoghost.holographicdisplays.bridge.bungeecord.pinger; + +import me.filoghost.holographicdisplays.core.DebugLogger; +import me.filoghost.holographicdisplays.disk.ServerAddress; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; + +public class PingResponse { + + private final String motd; + private final int onlinePlayers; + private final int maxPlayers; + + protected static PingResponse fromJson(String jsonString, ServerAddress address) { + if (jsonString == null || jsonString.isEmpty()) { + logInvalidResponse(jsonString, address); + return errorResponse("Invalid ping response (null or empty)"); + } + + Object jsonObject = JSONValue.parse(jsonString); + + if (!(jsonObject instanceof JSONObject)) { + logInvalidResponse(jsonString, address); + return errorResponse("Invalid ping response (wrong format)"); + } + + JSONObject json = (JSONObject) jsonObject; + + Object descriptionObject = json.get("description"); + + String motd; + int onlinePlayers = 0; + int maxPlayers = 0; + + if (descriptionObject == null) { + logInvalidResponse(jsonString, address); + return errorResponse("Invalid ping response (description not found)"); + } + + if (descriptionObject instanceof JSONObject) { + Object text = ((JSONObject) descriptionObject).get("text"); + if (text == null) { + logInvalidResponse(jsonString, address); + return errorResponse("Invalid ping response (text not found)"); + } + motd = text.toString(); + } else { + motd = descriptionObject.toString(); + } + + Object playersObject = json.get("players"); + + if (playersObject instanceof JSONObject) { + JSONObject playersJson = (JSONObject) playersObject; + + Object onlineObject = playersJson.get("online"); + if (onlineObject instanceof Number) { + onlinePlayers = ((Number) onlineObject).intValue(); + } + + Object maxObject = playersJson.get("max"); + if (maxObject instanceof Number) { + maxPlayers = ((Number) maxObject).intValue(); + } + } + + return new PingResponse(motd, onlinePlayers, maxPlayers); + } + + private static void logInvalidResponse(String responseJsonString, ServerAddress address) { + DebugLogger.warning("Received invalid JSON response from IP \"" + address + "\": " + responseJsonString); + } + + private static PingResponse errorResponse(String error) { + return new PingResponse(error, 0, 0); + } + + private PingResponse(String motd, int onlinePlayers, int maxPlayers) { + this.motd = motd; + this.onlinePlayers = onlinePlayers; + this.maxPlayers = maxPlayers; + } + + public String getMotd() { + return motd; + } + + public int getOnlinePlayers() { + return onlinePlayers; + } + + public int getMaxPlayers() { + return maxPlayers; + } + +} diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/pinger/ServerPinger.java b/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/pinger/ServerPinger.java new file mode 100644 index 00000000..2dc48dcc --- /dev/null +++ b/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/pinger/ServerPinger.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) filoghost and contributors + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package me.filoghost.holographicdisplays.bridge.bungeecord.pinger; + +import me.filoghost.holographicdisplays.disk.ServerAddress; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.Socket; +import java.nio.charset.StandardCharsets; + +public class ServerPinger { + + public static PingResponse fetchData(final ServerAddress serverAddress, int timeout) throws IOException { + try (Socket socket = openSocket(serverAddress)) { + socket.setSoTimeout(timeout); + DataOutputStream out = new DataOutputStream(socket.getOutputStream()); + DataInputStream in = new DataInputStream(socket.getInputStream()); + + // Handshake packet + ByteArrayOutputStream handshakeBytes = new ByteArrayOutputStream(); + DataOutputStream handshakeOut = new DataOutputStream(handshakeBytes); + handshakeOut.writeByte(0x00); // Packet ID + writeVarInt(handshakeOut, 4); // Protocol version + writeString(handshakeOut, serverAddress.getAddress()); + handshakeOut.writeShort(serverAddress.getPort()); + writeVarInt(handshakeOut, 1); // Next state: status request + writeByteArray(out, handshakeBytes.toByteArray()); + + // Status request packet + writeByteArray(out, new byte[]{ 0x00 }); // Packet ID + + // Response packet + readVarInt(in); // Packet size + readVarInt(in); // Packet ID + String responseJson = readString(in); + + return PingResponse.fromJson(responseJson, serverAddress); + } + } + + private static Socket openSocket(ServerAddress serverAddress) throws IOException { + return new Socket(serverAddress.getAddress(), serverAddress.getPort()); + } + + private static String readString(DataInputStream in) throws IOException { + byte[] bytes = readByteArray(in); + return new String(bytes, StandardCharsets.UTF_8); + } + + private static void writeString(DataOutputStream out, String s) throws IOException { + byte[] bytes = s.getBytes(StandardCharsets.UTF_8); + writeByteArray(out, bytes); + } + + private static byte[] readByteArray(DataInputStream in) throws IOException { + int length = readVarInt(in); + byte[] bytes = new byte[length]; + in.readFully(bytes); + return bytes; + } + + private static void writeByteArray(DataOutputStream out, byte[] bytes) throws IOException { + writeVarInt(out, bytes.length); + out.write(bytes); + } + + private static int readVarInt(DataInputStream in) throws IOException { + int i = 0; + int j = 0; + while (true) { + int k = in.readByte(); + i |= (k & 0x7F) << j++ * 7; + if (j > 5) { + throw new RuntimeException("VarInt too big"); + } + if ((k & 0x80) != 0x80) { + return i; + } + } + } + + private static void writeVarInt(DataOutputStream out, int paramInt) throws IOException { + while ((paramInt & 0xFFFFFF80) != 0x0) { + out.writeByte((paramInt & 0x7F) | 0x80); + paramInt >>>= 7; + } + out.writeByte(paramInt); + } + +} diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/PacketUtils.java b/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/PacketUtils.java deleted file mode 100644 index 63b91159..00000000 --- a/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/PacketUtils.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) filoghost and contributors - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ -package me.filoghost.holographicdisplays.bridge.bungeecord.serverpinger; - -import java.io.Closeable; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; - -class PacketUtils { - - public static void writeString(final DataOutputStream out, final String s, final Charset charset) throws IOException { - if (charset == StandardCharsets.UTF_8) { - writeVarInt(out, s.length()); - } else { - out.writeShort(s.length()); - } - out.write(s.getBytes(charset)); - } - - public static int readVarInt(final DataInputStream in) throws IOException { - int i = 0; - int j = 0; - while (true) { - final int k = in.readByte(); - i |= (k & 0x7F) << j++ * 7; - if (j > 5) { - throw new RuntimeException("VarInt too big"); - } - if ((k & 0x80) != 0x80) { - return i; - } - } - } - - public static void writeVarInt(final DataOutputStream out, int paramInt) throws IOException { - while ((paramInt & 0xFFFFFF80) != 0x0) { - out.write((paramInt & 0x7F) | 0x80); - paramInt >>>= 7; - } - out.write(paramInt); - } - - public static void closeQuietly(Closeable closeable) { - try { - if (closeable != null) { - closeable.close(); - } - } catch (IOException ignored) {} - } - -} diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/PingResponse.java b/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/PingResponse.java deleted file mode 100644 index b5f7e135..00000000 --- a/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/PingResponse.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) filoghost and contributors - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ -package me.filoghost.holographicdisplays.bridge.bungeecord.serverpinger; - -import me.filoghost.holographicdisplays.disk.ServerAddress; -import me.filoghost.holographicdisplays.core.DebugLogger; -import org.json.simple.JSONObject; -import org.json.simple.JSONValue; - -public class PingResponse -{ - private boolean isOnline; - private String motd; - private int onlinePlayers; - private int maxPlayers; - - public PingResponse(String jsonString, ServerAddress address) { - if (jsonString == null || jsonString.isEmpty()) { - motd = "Invalid ping response"; - DebugLogger.warning("Received empty Json response from IP \"" + address.toString() + "\"."); - return; - } - - Object jsonObject = JSONValue.parse(jsonString); - - if (!(jsonObject instanceof JSONObject)) { - motd = "Invalid ping response"; - DebugLogger.warning("Received invalid Json response from IP \"" + address.toString() + "\": " + jsonString); - return; - } - - JSONObject json = (JSONObject) jsonObject; - isOnline = true; - - Object descriptionObject = json.get("description"); - - if (descriptionObject != null) { - if (descriptionObject instanceof JSONObject) { - Object text = ((JSONObject) descriptionObject).get("text"); - if (text != null) { - motd = text.toString(); - } else { - motd = "Invalid ping response (text not found)"; - } - } else { - motd = descriptionObject.toString(); - } - } else { - motd = "Invalid ping response (description not found)"; - DebugLogger.warning("Received invalid Json response from IP \"" + address.toString() + "\": " + jsonString); - } - - Object playersObject = json.get("players"); - - if (playersObject instanceof JSONObject) { - JSONObject playersJson = (JSONObject) playersObject; - - Object onlineObject = playersJson.get("online"); - if (onlineObject instanceof Number) { - onlinePlayers = ((Number) onlineObject).intValue(); - } - - Object maxObject = playersJson.get("max"); - if (maxObject instanceof Number) { - maxPlayers = ((Number) maxObject).intValue(); - } - } - } - - public boolean isOnline() { - return isOnline; - } - - public String getMotd() { - return motd; - } - - public int getOnlinePlayers() { - return onlinePlayers; - } - - public int getMaxPlayers() { - return maxPlayers; - } - -} diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerPinger.java b/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerPinger.java deleted file mode 100644 index b42d1bbf..00000000 --- a/plugin/src/main/java/me/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerPinger.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) filoghost and contributors - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ -package me.filoghost.holographicdisplays.bridge.bungeecord.serverpinger; - -import me.filoghost.holographicdisplays.disk.ServerAddress; - -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.net.Socket; -import java.nio.charset.StandardCharsets; - -public class ServerPinger { - - public static PingResponse fetchData(final ServerAddress serverAddress, int timeout) throws IOException { - Socket socket = null; - DataOutputStream dataOut = null; - DataInputStream dataIn = null; - - try { - socket = new Socket(serverAddress.getAddress(), serverAddress.getPort()); - socket.setSoTimeout(timeout); - dataOut = new DataOutputStream(socket.getOutputStream()); - dataIn = new DataInputStream(socket.getInputStream()); - final ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); - final DataOutputStream handshake = new DataOutputStream(byteOut); - handshake.write(0); - PacketUtils.writeVarInt(handshake, 4); - PacketUtils.writeString(handshake, serverAddress.getAddress(), StandardCharsets.UTF_8); - handshake.writeShort(serverAddress.getPort()); - PacketUtils.writeVarInt(handshake, 1); - byte[] bytes = byteOut.toByteArray(); - PacketUtils.writeVarInt(dataOut, bytes.length); - dataOut.write(bytes); - bytes = new byte[] { 0 }; - PacketUtils.writeVarInt(dataOut, bytes.length); - dataOut.write(bytes); - PacketUtils.readVarInt(dataIn); - PacketUtils.readVarInt(dataIn); - final byte[] responseData = new byte[PacketUtils.readVarInt(dataIn)]; - dataIn.readFully(responseData); - final String jsonString = new String(responseData, StandardCharsets.UTF_8); - return new PingResponse(jsonString, serverAddress); - } finally { - PacketUtils.closeQuietly(dataOut); - PacketUtils.closeQuietly(dataIn); - PacketUtils.closeQuietly(socket); - } - } - -} diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/disk/Configuration.java b/plugin/src/main/java/me/filoghost/holographicdisplays/disk/Configuration.java index 4ea464d2..11dd261d 100644 --- a/plugin/src/main/java/me/filoghost/holographicdisplays/disk/Configuration.java +++ b/plugin/src/main/java/me/filoghost/holographicdisplays/disk/Configuration.java @@ -19,8 +19,8 @@ import org.bukkit.ChatColor; import java.time.DateTimeException; import java.time.ZoneId; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.List; +import java.util.HashMap; +import java.util.Map; public class Configuration { @@ -41,7 +41,7 @@ public class Configuration { public static String pingerStatusOnline; public static String pingerStatusOffline; public static boolean pingerTrimMotd; - public static List pingerServers; + public static Map pingerServerAddresses; public static void load(MainConfigModel config, ErrorCollector errorCollector) { spaceBetweenLines = config.spaceBetweenLines; @@ -61,13 +61,13 @@ public class Configuration { pingerStatusOnline = StringConverter.toReadableFormat(config.pingerStatusOnline); pingerStatusOffline = StringConverter.toReadableFormat(config.pingerStatusOffline); pingerTrimMotd = config.pingerTrimMotd; - - pingerServers = new ArrayList<>(); + + pingerServerAddresses = new HashMap<>(); if (pingerEnabled) { for (String singleServer : config.pingerServers) { ServerAddress serverAddress = parseServerAddress(singleServer, errorCollector); if (serverAddress != null) { - pingerServers.add(serverAddress); + pingerServerAddresses.put(serverAddress.getName(), serverAddress); } } } diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/placeholder/PlaceholdersManager.java b/plugin/src/main/java/me/filoghost/holographicdisplays/placeholder/PlaceholdersManager.java index 2409241d..4d999ee4 100644 --- a/plugin/src/main/java/me/filoghost/holographicdisplays/placeholder/PlaceholdersManager.java +++ b/plugin/src/main/java/me/filoghost/holographicdisplays/placeholder/PlaceholdersManager.java @@ -5,12 +5,15 @@ */ package me.filoghost.holographicdisplays.placeholder; +import me.filoghost.fcommons.Strings; import me.filoghost.fcommons.logging.Log; import me.filoghost.holographicdisplays.api.placeholder.PlaceholderReplacer; +import me.filoghost.holographicdisplays.bridge.bungeecord.ServerInfo; import me.filoghost.holographicdisplays.bridge.bungeecord.BungeeServerTracker; import me.filoghost.holographicdisplays.core.Utils; import me.filoghost.holographicdisplays.core.hologram.StandardTextLine; import me.filoghost.holographicdisplays.core.nms.entity.NMSArmorStand; +import me.filoghost.holographicdisplays.disk.Configuration; import me.filoghost.holographicdisplays.task.WorldPlayerCounterTask; import org.bukkit.Bukkit; import org.bukkit.plugin.Plugin; @@ -25,6 +28,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public class PlaceholdersManager { + + private static final String PINGER_NOT_ENABLED_ERROR = "[Please enable pinger]"; private static final Pattern BUNGEE_ONLINE_PATTERN = makePlaceholderWithArgsPattern("online"); private static final Pattern BUNGEE_MAX_PATTERN = makePlaceholderWithArgsPattern("max_players"); @@ -170,28 +175,22 @@ public class PlaceholdersManager { } final String serverName = extractArgumentFromPlaceholder(matcher); - bungeeServerTracker.track(serverName); // Track this server. if (serverName.contains(",")) { - String[] split = serverName.split(","); - for (int i = 0; i < split.length; i++) { - split[i] = split[i].trim(); - } - - final String[] serversToTrack = split; + String[] serversToTrack = Strings.splitAndTrim(serverName, ","); // Add it to tracked servers. bungeeReplacers.put(matcher.group(), () -> { int count = 0; for (String serverToTrack : serversToTrack) { - count += bungeeServerTracker.getPlayersOnline(serverToTrack); + count += bungeeServerTracker.getCurrentServerInfo(serverToTrack).getOnlinePlayers(); } return String.valueOf(count); }); } else { // Normal, single tracked server. bungeeReplacers.put(matcher.group(), () -> { - return String.valueOf(bungeeServerTracker.getPlayersOnline(serverName)); + return String.valueOf(bungeeServerTracker.getCurrentServerInfo(serverName).getOnlinePlayers()); }); } } @@ -204,11 +203,14 @@ public class PlaceholdersManager { } final String serverName = extractArgumentFromPlaceholder(matcher); - bungeeServerTracker.track(serverName); // Track this server. // Add it to tracked servers. bungeeReplacers.put(matcher.group(), () -> { - return bungeeServerTracker.getMaxPlayers(serverName); + if (!Configuration.pingerEnabled) { + return PINGER_NOT_ENABLED_ERROR; + } + + return String.valueOf(bungeeServerTracker.getCurrentServerInfo(serverName).getMaxPlayers()); }); } @@ -220,11 +222,14 @@ public class PlaceholdersManager { } final String serverName = extractArgumentFromPlaceholder(matcher); - bungeeServerTracker.track(serverName); // Track this server. // Add it to tracked servers. bungeeReplacers.put(matcher.group(), () -> { - return bungeeServerTracker.getMotd1(serverName); + if (!Configuration.pingerEnabled) { + return PINGER_NOT_ENABLED_ERROR; + } + + return bungeeServerTracker.getCurrentServerInfo(serverName).getMotdLine1(); }); } @@ -236,11 +241,14 @@ public class PlaceholdersManager { } final String serverName = extractArgumentFromPlaceholder(matcher); - bungeeServerTracker.track(serverName); // Track this server. // Add it to tracked servers. bungeeReplacers.put(matcher.group(), () -> { - return bungeeServerTracker.getMotd2(serverName); + if (!Configuration.pingerEnabled) { + return PINGER_NOT_ENABLED_ERROR; + } + + return bungeeServerTracker.getCurrentServerInfo(serverName).getMotdLine2(); }); } @@ -252,11 +260,19 @@ public class PlaceholdersManager { } final String serverName = extractArgumentFromPlaceholder(matcher); - bungeeServerTracker.track(serverName); // Track this server. // Add it to tracked servers. bungeeReplacers.put(matcher.group(), () -> { - return bungeeServerTracker.getOnlineStatus(serverName); + if (!Configuration.pingerEnabled) { + return PINGER_NOT_ENABLED_ERROR; + } + + ServerInfo serverInfo = bungeeServerTracker.getCurrentServerInfo(serverName); + if (serverInfo.isOnline()) { + return Configuration.pingerStatusOnline; + } else { + return Configuration.pingerStatusOffline; + } }); } diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/task/BungeeCleanupTask.java b/plugin/src/main/java/me/filoghost/holographicdisplays/task/BungeeCleanupTask.java deleted file mode 100644 index dc8783e6..00000000 --- a/plugin/src/main/java/me/filoghost/holographicdisplays/task/BungeeCleanupTask.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) filoghost and contributors - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ -package me.filoghost.holographicdisplays.task; - -import me.filoghost.holographicdisplays.bridge.bungeecord.BungeeServerInfo; -import me.filoghost.holographicdisplays.bridge.bungeecord.BungeeServerTracker; -import me.filoghost.holographicdisplays.core.DebugLogger; - -import java.util.Iterator; -import java.util.Map.Entry; -import java.util.concurrent.TimeUnit; - -/** - * A task to remove unused server data in the server tracker. - */ -public class BungeeCleanupTask implements Runnable { - - private static final long MAX_INACTIVITY = TimeUnit.MINUTES.toMillis(10); - - private final BungeeServerTracker bungeeServerTracker; - - public BungeeCleanupTask(BungeeServerTracker bungeeServerTracker) { - this.bungeeServerTracker = bungeeServerTracker; - } - - @Override - public void run() { - long now = System.currentTimeMillis(); - Iterator> iter = bungeeServerTracker.getTrackedServers().entrySet().iterator(); - - while (iter.hasNext()) { - Entry next = iter.next(); - long lastRequest = next.getValue().getLastRequest(); - - if (lastRequest != 0 && now - lastRequest > MAX_INACTIVITY) { - // Don't track that server anymore. - iter.remove(); - DebugLogger.info("Removed bungee server \"" + next.getKey() + "\" from tracking due to inactivity."); - } - } - } - -}