From 782e83be5d8a2c2612c77b1a917b6ce03222216b Mon Sep 17 00:00:00 2001 From: filoghost Date: Tue, 30 Dec 2014 12:55:14 +0100 Subject: [PATCH] Added the ability to ping any server (online status, motd, max players) + smaller tweaks. --- .../HolographicDisplays.java | 8 + .../bridge/bungeecord/BungeeChannel.java | 4 +- .../bridge/bungeecord/BungeeServerInfo.java | 42 ++++- .../bungeecord/BungeeServerTracker.java | 146 ++++++++++++++++-- .../bungeecord/serverpinger/PacketUtils.java | 67 ++++++++ .../serverpinger/ServerAddress.java | 21 +++ .../bungeecord/serverpinger/ServerPinger.java | 18 +++ .../serverpinger/ServerPingerPostNetty.java | 55 +++++++ .../serverpinger/ServerPingerPreNetty.java | 47 ++++++ .../bungeecord/serverpinger/ServerStatus.java | 54 +++++++ .../commands/main/subs/ReloadCommand.java | 2 +- .../holographicdisplays/disk/ConfigNode.java | 8 + .../disk/Configuration.java | 55 ++++++- .../placeholder/PlaceholdersManager.java | 94 ++++++++++- .../task/BungeeCleanupTask.java | 7 +- .../util/DebugHandler.java | 16 +- .../holographicdisplays/util/Utils.java | 18 +++ 17 files changed, 627 insertions(+), 35 deletions(-) create mode 100644 HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/PacketUtils.java create mode 100644 HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerAddress.java create mode 100644 HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerPinger.java create mode 100644 HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerPingerPostNetty.java create mode 100644 HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerPingerPreNetty.java create mode 100644 HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerStatus.java diff --git a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/HolographicDisplays.java b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/HolographicDisplays.java index 45bac637..1cd5543b 100644 --- a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/HolographicDisplays.java +++ b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/HolographicDisplays.java @@ -38,6 +38,9 @@ public class HolographicDisplays extends JavaPlugin { // Since 1.8 we use armor stands instead of wither skulls. private static boolean is1_8; + // Used for the server pinger. + private static boolean isPreNetty; + // True if ProtocolLib is installed and successfully loaded. private static boolean useProtocolLib; @@ -83,6 +86,7 @@ public class HolographicDisplays extends JavaPlugin { if ("1.6.4".equals(version)) { version = "v1_6_R3"; + isPreNetty = true; } else if ("1.7.2".equals(version)) { version = "v1_7_R1"; } else if ("1.7.5".equals(version)) { @@ -222,6 +226,10 @@ public class HolographicDisplays extends JavaPlugin { return is1_8; } + public static boolean isPreNetty() { + return isPreNetty; + } + private static void printWarnAndDisable(String... messages) { StringBuffer buffer = new StringBuffer("\n "); for (String message : messages) { diff --git a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/BungeeChannel.java b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/BungeeChannel.java index 49dd4c51..967db9e6 100644 --- a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/BungeeChannel.java +++ b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/BungeeChannel.java @@ -50,7 +50,9 @@ public class BungeeChannel implements PluginMessageListener { if (in.available() > 0) { int online = in.readInt(); - BungeeServerTracker.handlePing(server, online); + + BungeeServerInfo serverInfo = BungeeServerTracker.getOrCreateServerInfo(server); + serverInfo.setOnlinePlayers(online); } } diff --git a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/BungeeServerInfo.java b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/BungeeServerInfo.java index 7151c08a..1da3d851 100644 --- a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/BungeeServerInfo.java +++ b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/BungeeServerInfo.java @@ -2,12 +2,24 @@ package com.gmail.filoghost.holographicdisplays.bridge.bungeecord; public class BungeeServerInfo { + private boolean isOnline; private int onlinePlayers; + private int maxPlayers; + private String motd; // Should never be null private long lastRequest; - protected BungeeServerInfo(int onlinePlayers, long lastRequest) { - this.onlinePlayers = onlinePlayers; - this.lastRequest = lastRequest; + protected BungeeServerInfo() { + isOnline = true; + this.motd = ""; + updateLastRequest(); + } + + public boolean isOnline() { + return isOnline; + } + + public void setOnline(boolean isOnline) { + this.isOnline = isOnline; } public int getOnlinePlayers() { @@ -17,13 +29,33 @@ public class BungeeServerInfo { public void setOnlinePlayers(int onlinePlayers) { this.onlinePlayers = onlinePlayers; } + + public int getMaxPlayers() { + return maxPlayers; + } + + public void setMaxPlayers(int maxPlayers) { + this.maxPlayers = maxPlayers; + } + + public String getMotd() { + return motd; + } + + public void setMotd(String motd) { + if (motd == null) { + motd = ""; + } + + this.motd = motd; + } public long getLastRequest() { return lastRequest; } - public void setLastRequest(long lastRequest) { - this.lastRequest = lastRequest; + public void updateLastRequest() { + this.lastRequest = System.currentTimeMillis(); } } diff --git a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/BungeeServerTracker.java b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/BungeeServerTracker.java index 5a8ba914..da272b6a 100644 --- a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/BungeeServerTracker.java +++ b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/BungeeServerTracker.java @@ -1,16 +1,28 @@ package com.gmail.filoghost.holographicdisplays.bridge.bungeecord; -import java.util.HashMap; +import java.io.IOException; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; import org.bukkit.Bukkit; +import org.bukkit.scheduler.BukkitRunnable; import com.gmail.filoghost.holographicdisplays.HolographicDisplays; +import com.gmail.filoghost.holographicdisplays.bridge.bungeecord.serverpinger.ServerAddress; +import com.gmail.filoghost.holographicdisplays.bridge.bungeecord.serverpinger.ServerPinger; +import com.gmail.filoghost.holographicdisplays.bridge.bungeecord.serverpinger.ServerStatus; +import com.gmail.filoghost.holographicdisplays.disk.Configuration; +import com.gmail.filoghost.holographicdisplays.util.DebugHandler; public class BungeeServerTracker { - private static Map trackedServers = new HashMap(); + private static Map trackedServers = new ConcurrentHashMap(); private static int taskID = -1; + + private static ServerPinger pinger = HolographicDisplays.isPreNetty() ? ServerPinger.PRE_NETTY_REWRITE : ServerPinger.POST_NETTY_REWRITE; public static void resetTrackedServers() { trackedServers.clear(); @@ -18,9 +30,12 @@ public class BungeeServerTracker { public static void track(String server) { if (!trackedServers.containsKey(server)) { - BungeeServerInfo info = new BungeeServerInfo(0, System.currentTimeMillis()); + BungeeServerInfo info = new BungeeServerInfo(); trackedServers.put(server, info); - BungeeChannel.getInstance().askPlayerCount(server); + + if (!Configuration.pingerEnable) { + BungeeChannel.getInstance().askPlayerCount(server); + } } } @@ -28,26 +43,76 @@ public class BungeeServerTracker { trackedServers.remove(server); } - // Handle a successful ping. - protected static void handlePing(String server, int online) { + protected static BungeeServerInfo getOrCreateServerInfo(String server) { BungeeServerInfo info = trackedServers.get(server); if (info == null) { - info = new BungeeServerInfo(online, System.currentTimeMillis()); + info = new BungeeServerInfo(); trackedServers.put(server, info); - } else { - info.setOnlinePlayers(online); } + + return info; } - - public static int getPlayersOnline(String server) { + + public static String getPlayersOnline(String server) { BungeeServerInfo info = trackedServers.get(server); if (info != null) { - info.setLastRequest(System.currentTimeMillis()); - return info.getOnlinePlayers(); + info.updateLastRequest(); + return String.valueOf(info.getOnlinePlayers()); } else { // It was not tracked, add it. track(server); - return 0; + return "[Loading...]"; + } + } + + public static String getMaxPlayers(String server) { + + if (!Configuration.pingerEnable) { + return "[Please enable pinger]"; + } + + 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 "[Loading...]"; + } + } + + public static String getMotd(String server) { + + if (!Configuration.pingerEnable) { + return "[Please enable pinger]"; + } + + BungeeServerInfo info = trackedServers.get(server); + if (info != null) { + info.updateLastRequest(); + return info.getMotd(); + } else { + // It was not tracked, add it. + track(server); + return "[Loading...]"; + } + } + + public static String getOnlineStatus(String server) { + + if (!Configuration.pingerEnable) { + return "[Please enable pinger]"; + } + + 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 "[Loading...]"; } } @@ -62,10 +127,59 @@ public class BungeeServerTracker { } taskID = Bukkit.getScheduler().scheduleSyncRepeatingTask(HolographicDisplays.getInstance(), new Runnable() { + + @Override public void run() { - for (String server : trackedServers.keySet()) { - BungeeChannel.getInstance().askPlayerCount(server); + + if (Configuration.pingerEnable) { + new BukkitRunnable() { + + @Override + public void run() { + for (Entry entry : Configuration.pingerServers.entrySet()) { + + BungeeServerInfo serverInfo = getOrCreateServerInfo(entry.getKey()); + boolean displayOffline = false; + + try { + ServerStatus data = pinger.fetchData(entry.getValue(), 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) { + displayOffline = true; + } catch (UnknownHostException e) { + HolographicDisplays.getInstance().getLogger().warning("Couldn't fetch data from " + entry.getKey() + "(" + entry.getValue().toString() + "): unknown host address."); + displayOffline = true; + } catch (IOException e) { + displayOffline = true; + } catch (Exception e) { + displayOffline = true; + HolographicDisplays.getInstance().getLogger().warning("Couldn't fetch data from " + entry.getKey() + "(" + entry.getValue().toString() + "), unhandled exception: " + e.toString()); + DebugHandler.handleDebugException(e); + } + + if (displayOffline) { + serverInfo.setOnline(false); + serverInfo.setOnlinePlayers(0); + serverInfo.setMaxPlayers(0); + serverInfo.setMotd(Configuration.pingerOfflineMotd); + } + } + } + }.runTaskAsynchronously(HolographicDisplays.getInstance()); + + } else { + for (String server : trackedServers.keySet()) { + BungeeChannel.getInstance().askPlayerCount(server); + } } + } }, 0, refreshSeconds * 20); } diff --git a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/PacketUtils.java b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/PacketUtils.java new file mode 100644 index 00000000..f0cb59de --- /dev/null +++ b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/PacketUtils.java @@ -0,0 +1,67 @@ +package com.gmail.filoghost.holographicdisplays.bridge.bungeecord.serverpinger; + +import java.lang.RuntimeException; +import java.io.Closeable; +import java.io.DataInputStream; +import java.io.IOException; +import java.lang.Character; +import java.lang.String; +import java.io.DataOutputStream; +import java.nio.charset.Charset; + +class PacketUtils +{ + public static final Charset UTF16BE = Charset.forName("UTF-16BE");; + public static final Charset UTF8 = Charset.forName("UTF-8"); + + public static void a(final DataOutputStream out, final String s) throws IOException { + final int len = s.length(); + final byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte)((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16)); + } + out.write(data); + } + + public static void writeString(final DataOutputStream out, final String s, final Charset charset) throws IOException { + if (charset == PacketUtils.UTF8) { + 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 e) { } + } + +} diff --git a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerAddress.java b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerAddress.java new file mode 100644 index 00000000..d3d2ccc6 --- /dev/null +++ b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerAddress.java @@ -0,0 +1,21 @@ +package com.gmail.filoghost.holographicdisplays.bridge.bungeecord.serverpinger; + +public class ServerAddress { + + private String ip; + private int port; + + public ServerAddress(String ip, int port) { + this.ip = ip; + this.port = port; + } + + public String getAddress() { + return ip; + } + + public int getPort() { + return port; + } + +} diff --git a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerPinger.java b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerPinger.java new file mode 100644 index 00000000..05c691f6 --- /dev/null +++ b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerPinger.java @@ -0,0 +1,18 @@ +package com.gmail.filoghost.holographicdisplays.bridge.bungeecord.serverpinger; + +import java.io.IOException; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; + + +public abstract class ServerPinger { + + // For 1.7 and higher + public static final ServerPinger POST_NETTY_REWRITE = new ServerPingerPostNetty(); + + // For 1.6 and lower + public static final ServerPinger PRE_NETTY_REWRITE = new ServerPingerPreNetty(); + + public abstract ServerStatus fetchData(final ServerAddress serverAddress, int timeout) throws SocketTimeoutException, UnknownHostException, IOException, Exception; + +} diff --git a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerPingerPostNetty.java b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerPingerPostNetty.java new file mode 100644 index 00000000..d8e733fb --- /dev/null +++ b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerPingerPostNetty.java @@ -0,0 +1,55 @@ +package com.gmail.filoghost.holographicdisplays.bridge.bungeecord.serverpinger; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; + +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; + +final class ServerPingerPostNetty extends ServerPinger { + + @Override + public ServerStatus fetchData(final ServerAddress serverAddress, int timeout) throws SocketTimeoutException, UnknownHostException, IOException, Exception { + + 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(), PacketUtils.UTF8); + 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, PacketUtils.UTF8); + return new ServerStatus((JSONObject) JSONValue.parse(jsonString)); + } + finally { + PacketUtils.closeQuietly(dataOut); + PacketUtils.closeQuietly(dataIn); + PacketUtils.closeQuietly(socket); + } + } + +} diff --git a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerPingerPreNetty.java b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerPingerPreNetty.java new file mode 100644 index 00000000..0d5e2aff --- /dev/null +++ b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerPingerPreNetty.java @@ -0,0 +1,47 @@ +package com.gmail.filoghost.holographicdisplays.bridge.bungeecord.serverpinger; + +import java.lang.Override; +import java.io.IOException; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; +import java.lang.Integer; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.net.Socket; +import java.lang.String; + +final class ServerPingerPreNetty extends ServerPinger { + + @Override + public ServerStatus fetchData(final ServerAddress serverAddress, int timeout) throws SocketTimeoutException, UnknownHostException, IOException, Exception { + + 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()); + PacketUtils.a(dataOut, "FE"); + PacketUtils.a(dataOut, "01"); + dataIn.readByte(); + dataIn.readByte(); + final int length = dataIn.readByte() * 2; + final byte[] bytes = new byte[length]; + dataIn.readFully(bytes); + socket.close(); + final String[] info = new String(bytes, PacketUtils.UTF16BE).split(String.valueOf('\0')); + final ServerStatus response = new ServerStatus(true, info[3], Integer.parseInt(info[4]), Integer.parseInt(info[5])); + // String versionName = info[2]; + // String protocol = info[1]; + return response; + } + finally { + PacketUtils.closeQuietly(dataIn); + PacketUtils.closeQuietly(dataOut); + PacketUtils.closeQuietly(socket); + } + } +} diff --git a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerStatus.java b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerStatus.java new file mode 100644 index 00000000..5b3afbd7 --- /dev/null +++ b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/bridge/bungeecord/serverpinger/ServerStatus.java @@ -0,0 +1,54 @@ +package com.gmail.filoghost.holographicdisplays.bridge.bungeecord.serverpinger; + +import java.lang.Override; +import java.lang.String; + +import org.json.simple.JSONObject; + +public class ServerStatus +{ + private boolean isOnline; + private String motd; + private int onlinePlayers; + private int maxPlayers; + + public ServerStatus(boolean isOnline, String motd, int onlinePlayers, int maxPlayers) { + this.isOnline = isOnline; + this.motd = motd; + this.onlinePlayers = onlinePlayers; + this.maxPlayers = maxPlayers; + } + + public ServerStatus(JSONObject json) { + isOnline = true; + motd = ((String) json.get("description")).replace("\n", ""); + + JSONObject playersJson = (JSONObject) json.get("players"); + onlinePlayers = ((Long) playersJson.get("online")).intValue(); + maxPlayers = ((Long) playersJson.get("max")).intValue(); + } + + public boolean isOnline() { + return isOnline; + } + + public String getMotd() { + return motd; + } + + public int getOnlinePlayers() { + return onlinePlayers; + } + + public int getMaxPlayers() { + return maxPlayers; + } + + @Override + public String toString() { + return "ServerStatus [motd=" + motd + ", onlinePlayers=" + onlinePlayers + ", maxPlayers=" + maxPlayers + "]"; + } + + + +} diff --git a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/commands/main/subs/ReloadCommand.java b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/commands/main/subs/ReloadCommand.java index 2458e994..ce8b1154 100644 --- a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/commands/main/subs/ReloadCommand.java +++ b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/commands/main/subs/ReloadCommand.java @@ -49,9 +49,9 @@ public class ReloadCommand extends HologramSubCommand { long startMillis = System.currentTimeMillis(); + UnicodeSymbols.load(HolographicDisplays.getInstance()); Configuration.load(HolographicDisplays.getInstance()); BungeeServerTracker.startTask(Configuration.bungeeRefreshSeconds); - UnicodeSymbols.load(HolographicDisplays.getInstance()); HologramDatabase.loadYamlFile(HolographicDisplays.getInstance()); AnimationsRegister.loadAnimations(HolographicDisplays.getInstance()); PlaceholdersManager.untrackAll(); diff --git a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/disk/ConfigNode.java b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/disk/ConfigNode.java index c2889620..719e46f8 100644 --- a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/disk/ConfigNode.java +++ b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/disk/ConfigNode.java @@ -1,5 +1,7 @@ package com.gmail.filoghost.holographicdisplays.disk; +import java.util.Arrays; + public enum ConfigNode { SPACE_BETWEEN_LINES("space-between-lines", 0.02), @@ -9,6 +11,12 @@ public enum ConfigNode { UPDATE_NOTIFICATION("update-notification", true), BUNGEE_REFRESH_SECONDS("bungee.refresh-seconds", 3), BUNGEE_USE_REDIS_BUNGEE("bungee.use-RedisBungee", false), + BUNGEE_USE_FULL_PINGER("bungee.pinger.enable", false), + BUNGEE_PINGER_TIMEOUT("bungee.pinger.timeout", 2000), + BUNGEE_PINGER_OFFLINE_MOTD("bungee.pinger.offline-motd", "&cOffline, couldn't get the MOTD."), + BUNGEE_PINGER_ONLINE_FORMAT("bungee.pinger.status.online", "&aOnline"), + BUNGEE_PINGER_OFFLINE_FORMAT("bungee.pinger.status.offline", "&cOffline"), + BUNGEE_PINGER_SERVERS("bungee.pinger.servers", Arrays.asList("hub: 127.0.0.1:25565", "survival: 127.0.0.1:25566", "minigames: 127.0.0.1:25567")), TIME_FORMAT("time.format", "H:mm"), TIME_ZONE("time.zone", "GMT+1"), DEBUG("debug", false); diff --git a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/disk/Configuration.java b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/disk/Configuration.java index 07ba27f9..17d7d952 100644 --- a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/disk/Configuration.java +++ b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/disk/Configuration.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.TimeZone; import org.bukkit.ChatColor; @@ -12,6 +13,7 @@ import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.plugin.Plugin; +import com.gmail.filoghost.holographicdisplays.bridge.bungeecord.serverpinger.ServerAddress; import com.gmail.filoghost.holographicdisplays.util.Utils; /** @@ -29,10 +31,15 @@ public class Configuration { public static SimpleDateFormat timeFormat; public static int bungeeRefreshSeconds; - public static String bungeeOnlineFormat; - public static String bungeeOfflineFormat; public static boolean useRedisBungee; + public static boolean pingerEnable; + public static int pingerTimeout; + public static Map pingerServers; + public static String pingerOfflineMotd; + public static String pingerStatusOnline; + public static String pingerStatusOffline; + public static boolean debug; @@ -112,6 +119,50 @@ public class Configuration { transparencySymbol = StringConverter.toReadableFormat(config.getString(ConfigNode.TRANSPARENCY_SPACE.getPath())); bungeeRefreshSeconds = config.getInt(ConfigNode.BUNGEE_REFRESH_SECONDS.getPath()); useRedisBungee = config.getBoolean(ConfigNode.BUNGEE_USE_REDIS_BUNGEE.getPath()); + pingerEnable = config.getBoolean(ConfigNode.BUNGEE_USE_FULL_PINGER.getPath()); + pingerTimeout = config.getInt(ConfigNode.BUNGEE_PINGER_TIMEOUT.getPath()); + + pingerOfflineMotd = StringConverter.toReadableFormat(config.getString(ConfigNode.BUNGEE_PINGER_OFFLINE_MOTD.getPath())); + pingerStatusOnline = StringConverter.toReadableFormat(config.getString(ConfigNode.BUNGEE_PINGER_ONLINE_FORMAT.getPath())); + pingerStatusOffline = StringConverter.toReadableFormat(config.getString(ConfigNode.BUNGEE_PINGER_OFFLINE_FORMAT.getPath())); + + if (pingerTimeout <= 0) { + pingerTimeout = 1; + } + + pingerServers = Utils.newMap(); + + if (pingerEnable) { + for (String singleServer : config.getStringList(ConfigNode.BUNGEE_PINGER_SERVERS.getPath())) { + String[] nameAndAddress = singleServer.split(":", 2); + if (nameAndAddress.length < 2) { + plugin.getLogger().warning("The server info \"" + singleServer + "\" is not valid. There should be a name and an address, separated by a colon."); + continue; + } + + String name = nameAndAddress[0].trim(); + String address = nameAndAddress[1].replace(" ", ""); + + String ip; + int port; + + if (address.contains(":")) { + String[] ipAndPort = address.split(":", 2); + ip = ipAndPort[0]; + try { + port = Integer.parseInt(ipAndPort[1]); + } catch (NumberFormatException e) { + plugin.getLogger().warning("Invalid port number in the server info \"" + singleServer + "\"."); + continue; + } + } else { + ip = address; + port = 25565; // The default Minecraft port. + } + + pingerServers.put(name, new ServerAddress(ip, port)); + } + } debug = config.getBoolean(ConfigNode.DEBUG.getPath()); diff --git a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/placeholder/PlaceholdersManager.java b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/placeholder/PlaceholdersManager.java index f2c4d0b5..dd821c26 100644 --- a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/placeholder/PlaceholdersManager.java +++ b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/placeholder/PlaceholdersManager.java @@ -23,6 +23,9 @@ public class PlaceholdersManager { protected static Set linesToUpdate = Utils.newSet(); private static final Pattern BUNGEE_ONLINE_PATTERN = makePlaceholderWithArgsPattern("online"); + private static final Pattern BUNGEE_MAX_PATTERN = makePlaceholderWithArgsPattern("max"); + private static final Pattern BUNGEE_MOTD_PATTERN = makePlaceholderWithArgsPattern("motd"); + private static final Pattern BUNGEE_STATUS_PATTERN = makePlaceholderWithArgsPattern("status"); private static final Pattern ANIMATION_PATTERN = makePlaceholderWithArgsPattern("animation"); private static final Pattern WORLD_PATTERN = makePlaceholderWithArgsPattern("world"); @@ -113,6 +116,10 @@ public class PlaceholdersManager { Set normalPlaceholders = null; Map bungeeOnlinePlayersReplacers = null; + Map bungeeMaxPlayersReplacers = null; + Map bungeeStatusReplacers = null; + Map bungeeMotdReplacers = null; + Map worldsOnlinePlayersReplacers = null; Map animationsPlaceholders = null; @@ -165,11 +172,75 @@ public class PlaceholdersManager { @Override public String update() { - return String.valueOf(BungeeServerTracker.getPlayersOnline(serverName)); + return BungeeServerTracker.getPlayersOnline(serverName); } }); } + // BungeeCord max players pattern. + matcher = BUNGEE_MAX_PATTERN.matcher(name); + while (matcher.find()) { + + if (bungeeMaxPlayersReplacers == null) { + bungeeMaxPlayersReplacers = Utils.newMap(); + } + + final String serverName = extractArgumentFromPlaceholder(matcher); + BungeeServerTracker.track(serverName); // Track this server. + + // Add it to tracked servers. + bungeeMaxPlayersReplacers.put(matcher.group(), new PlaceholderReplacer() { + + @Override + public String update() { + return BungeeServerTracker.getMaxPlayers(serverName); + } + }); + } + + // BungeeCord motd pattern. + matcher = BUNGEE_MOTD_PATTERN.matcher(name); + while (matcher.find()) { + + if (bungeeMotdReplacers == null) { + bungeeMotdReplacers = Utils.newMap(); + } + + final String serverName = extractArgumentFromPlaceholder(matcher); + BungeeServerTracker.track(serverName); // Track this server. + + // Add it to tracked servers. + bungeeMotdReplacers.put(matcher.group(), new PlaceholderReplacer() { + + @Override + public String update() { + return BungeeServerTracker.getMotd(serverName); + } + }); + } + + // BungeeCord status pattern. + matcher = BUNGEE_STATUS_PATTERN.matcher(name); + while (matcher.find()) { + + if (bungeeStatusReplacers == null) { + bungeeStatusReplacers = Utils.newMap(); + } + + final String serverName = extractArgumentFromPlaceholder(matcher); + BungeeServerTracker.track(serverName); // Track this server. + + // Add it to tracked servers. + bungeeStatusReplacers.put(matcher.group(), new PlaceholderReplacer() { + + @Override + public String update() { + return BungeeServerTracker.getOnlineStatus(serverName); + } + }); + } + + // Animation pattern. matcher = ANIMATION_PATTERN.matcher(name); while (matcher.find()) { @@ -192,7 +263,8 @@ public class PlaceholdersManager { } } - if (normalPlaceholders != null || bungeeOnlinePlayersReplacers != null || worldsOnlinePlayersReplacers != null || animationsPlaceholders != null) { + if (Utils.isThereNonNull(normalPlaceholders, bungeeOnlinePlayersReplacers, bungeeMaxPlayersReplacers, bungeeMotdReplacers, bungeeStatusReplacers, worldsOnlinePlayersReplacers, animationsPlaceholders)) { + DynamicLineData lineData = new DynamicLineData(nameableEntity, name); if (normalPlaceholders != null) { @@ -203,6 +275,18 @@ public class PlaceholdersManager { lineData.getReplacers().putAll(bungeeOnlinePlayersReplacers); } + if (bungeeMaxPlayersReplacers != null) { + lineData.getReplacers().putAll(bungeeMaxPlayersReplacers); + } + + if (bungeeMotdReplacers != null) { + lineData.getReplacers().putAll(bungeeMotdReplacers); + } + + if (bungeeStatusReplacers != null) { + lineData.getReplacers().putAll(bungeeStatusReplacers); + } + if (worldsOnlinePlayersReplacers != null) { lineData.getReplacers().putAll(worldsOnlinePlayersReplacers); } @@ -236,19 +320,19 @@ public class PlaceholdersManager { if (!lineData.getPlaceholders().isEmpty()) { for (Placeholder placeholder : lineData.getPlaceholders()) { - newCustomName = newCustomName.replace(placeholder.getTextPlaceholder(), placeholder.getCurrentReplacement()); + newCustomName = newCustomName.replace(placeholder.getTextPlaceholder(), Utils.sanitize(placeholder.getCurrentReplacement())); } } if (!lineData.getReplacers().isEmpty()) { for (Entry entry : lineData.getReplacers().entrySet()) { - newCustomName = newCustomName.replace(entry.getKey(), entry.getValue().update()); + newCustomName = newCustomName.replace(entry.getKey(), Utils.sanitize(entry.getValue().update())); } } if (!lineData.getAnimations().isEmpty()) { for (Entry entry : lineData.getAnimations().entrySet()) { - newCustomName = newCustomName.replace(entry.getKey(), entry.getValue().getCurrentReplacement()); + newCustomName = newCustomName.replace(entry.getKey(), Utils.sanitize(entry.getValue().getCurrentReplacement())); } } diff --git a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/task/BungeeCleanupTask.java b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/task/BungeeCleanupTask.java index 39dd22f1..9aea7b0c 100644 --- a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/task/BungeeCleanupTask.java +++ b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/task/BungeeCleanupTask.java @@ -5,6 +5,7 @@ import java.util.Map.Entry; import com.gmail.filoghost.holographicdisplays.bridge.bungeecord.BungeeServerInfo; import com.gmail.filoghost.holographicdisplays.bridge.bungeecord.BungeeServerTracker; +import com.gmail.filoghost.holographicdisplays.util.DebugHandler; /** * A task to remove unused server data in the server tracker. @@ -16,12 +17,14 @@ public class BungeeCleanupTask implements Runnable { Iterator> iter = BungeeServerTracker.getTrackedServers().entrySet().iterator(); - while (iter.hasNext()) { - long lastRequest = iter.next().getValue().getLastRequest(); + while (iter.hasNext()) { + Entry next = iter.next(); + long lastRequest = next.getValue().getLastRequest(); if (lastRequest != 0 && System.currentTimeMillis() - lastRequest > 600000) { // 10 * 60 * 1000 = 10 minutes. // Don't track that server anymore. iter.remove(); + DebugHandler.logToConsole("Untracked bungee server \"" + next.getKey() + "\" due to inactivity."); } } } diff --git a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/util/DebugHandler.java b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/util/DebugHandler.java index 6d62f1e9..4558444e 100644 --- a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/util/DebugHandler.java +++ b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/util/DebugHandler.java @@ -6,15 +6,25 @@ import com.gmail.filoghost.holographicdisplays.disk.Configuration; public class DebugHandler { - public static void handleSpawnFail(HologramLine parentPiece) { + public static void logToConsole(String msg) { if (Configuration.debug) { - HolographicDisplays.getInstance().getLogger().warning("[Debug] Coulnd't spawn entity for this hologram: " + parentPiece.getParent().toString()); + HolographicDisplays.getInstance().getLogger().info("[Debug] " + msg); } } public static void handleAnimationLoadSuccess(String name, double speed) { + logToConsole("Successfully loaded animation '" + name + "', speed = " + speed + "."); + } + + public static void handleSpawnFail(HologramLine parentPiece) { if (Configuration.debug) { - HolographicDisplays.getInstance().getLogger().info("[Debug] Successfully loaded animation '" + name + "', speed = " + speed + "."); + HolographicDisplays.getInstance().getLogger().severe("[Debug] Coulnd't spawn entity for this hologram: " + parentPiece.getParent().toString()); + } + } + + public static void handleDebugException(Exception e) { + if (Configuration.debug) { + e.printStackTrace(); } } diff --git a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/util/Utils.java b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/util/Utils.java index 9daee09e..0e588a23 100644 --- a/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/util/Utils.java +++ b/HolographicDisplays/Plugin/com/gmail/filoghost/holographicdisplays/util/Utils.java @@ -106,4 +106,22 @@ public class Utils extends Object { public static String join(List elements, String separator) { return join(elements, separator, 0, elements.size()); } + + public static String sanitize(String s) { + return s != null ? s : "null"; + } + + public static boolean isThereNonNull(Object... objects) { + if (objects == null) { + return false; + } + + for (int i = 0; i < objects.length; i++) { + if (objects[i] != null) { + return true; + } + } + + return false; + } }