Added the ability to ping any server (online status, motd, max players)

+ smaller tweaks.
This commit is contained in:
filoghost 2014-12-30 12:55:14 +01:00
parent 896609d046
commit 782e83be5d
17 changed files with 627 additions and 35 deletions

View File

@ -38,6 +38,9 @@ public class HolographicDisplays extends JavaPlugin {
// Since 1.8 we use armor stands instead of wither skulls. // Since 1.8 we use armor stands instead of wither skulls.
private static boolean is1_8; private static boolean is1_8;
// Used for the server pinger.
private static boolean isPreNetty;
// True if ProtocolLib is installed and successfully loaded. // True if ProtocolLib is installed and successfully loaded.
private static boolean useProtocolLib; private static boolean useProtocolLib;
@ -83,6 +86,7 @@ public class HolographicDisplays extends JavaPlugin {
if ("1.6.4".equals(version)) { if ("1.6.4".equals(version)) {
version = "v1_6_R3"; version = "v1_6_R3";
isPreNetty = true;
} else if ("1.7.2".equals(version)) { } else if ("1.7.2".equals(version)) {
version = "v1_7_R1"; version = "v1_7_R1";
} else if ("1.7.5".equals(version)) { } else if ("1.7.5".equals(version)) {
@ -222,6 +226,10 @@ public class HolographicDisplays extends JavaPlugin {
return is1_8; return is1_8;
} }
public static boolean isPreNetty() {
return isPreNetty;
}
private static void printWarnAndDisable(String... messages) { private static void printWarnAndDisable(String... messages) {
StringBuffer buffer = new StringBuffer("\n "); StringBuffer buffer = new StringBuffer("\n ");
for (String message : messages) { for (String message : messages) {

View File

@ -50,7 +50,9 @@ public class BungeeChannel implements PluginMessageListener {
if (in.available() > 0) { if (in.available() > 0) {
int online = in.readInt(); int online = in.readInt();
BungeeServerTracker.handlePing(server, online);
BungeeServerInfo serverInfo = BungeeServerTracker.getOrCreateServerInfo(server);
serverInfo.setOnlinePlayers(online);
} }
} }

View File

@ -2,12 +2,24 @@ package com.gmail.filoghost.holographicdisplays.bridge.bungeecord;
public class BungeeServerInfo { public class BungeeServerInfo {
private boolean isOnline;
private int onlinePlayers; private int onlinePlayers;
private int maxPlayers;
private String motd; // Should never be null
private long lastRequest; private long lastRequest;
protected BungeeServerInfo(int onlinePlayers, long lastRequest) { protected BungeeServerInfo() {
this.onlinePlayers = onlinePlayers; isOnline = true;
this.lastRequest = lastRequest; this.motd = "";
updateLastRequest();
}
public boolean isOnline() {
return isOnline;
}
public void setOnline(boolean isOnline) {
this.isOnline = isOnline;
} }
public int getOnlinePlayers() { public int getOnlinePlayers() {
@ -18,12 +30,32 @@ public class BungeeServerInfo {
this.onlinePlayers = 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() { public long getLastRequest() {
return lastRequest; return lastRequest;
} }
public void setLastRequest(long lastRequest) { public void updateLastRequest() {
this.lastRequest = lastRequest; this.lastRequest = System.currentTimeMillis();
} }
} }

View File

@ -1,53 +1,118 @@
package com.gmail.filoghost.holographicdisplays.bridge.bungeecord; 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;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.scheduler.BukkitRunnable;
import com.gmail.filoghost.holographicdisplays.HolographicDisplays; 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 { public class BungeeServerTracker {
private static Map<String, BungeeServerInfo> trackedServers = new HashMap<String, BungeeServerInfo>(); private static Map<String, BungeeServerInfo> trackedServers = new ConcurrentHashMap<String, BungeeServerInfo>();
private static int taskID = -1; private static int taskID = -1;
private static ServerPinger pinger = HolographicDisplays.isPreNetty() ? ServerPinger.PRE_NETTY_REWRITE : ServerPinger.POST_NETTY_REWRITE;
public static void resetTrackedServers() { public static void resetTrackedServers() {
trackedServers.clear(); trackedServers.clear();
} }
public static void track(String server) { public static void track(String server) {
if (!trackedServers.containsKey(server)) { if (!trackedServers.containsKey(server)) {
BungeeServerInfo info = new BungeeServerInfo(0, System.currentTimeMillis()); BungeeServerInfo info = new BungeeServerInfo();
trackedServers.put(server, info); trackedServers.put(server, info);
if (!Configuration.pingerEnable) {
BungeeChannel.getInstance().askPlayerCount(server); BungeeChannel.getInstance().askPlayerCount(server);
} }
} }
}
public static void untrack(String server) { public static void untrack(String server) {
trackedServers.remove(server); trackedServers.remove(server);
} }
// Handle a successful ping. protected static BungeeServerInfo getOrCreateServerInfo(String server) {
protected static void handlePing(String server, int online) {
BungeeServerInfo info = trackedServers.get(server); BungeeServerInfo info = trackedServers.get(server);
if (info == null) { if (info == null) {
info = new BungeeServerInfo(online, System.currentTimeMillis()); info = new BungeeServerInfo();
trackedServers.put(server, info); trackedServers.put(server, info);
} else {
info.setOnlinePlayers(online);
}
} }
public static int getPlayersOnline(String server) { return info;
}
public static String getPlayersOnline(String server) {
BungeeServerInfo info = trackedServers.get(server); BungeeServerInfo info = trackedServers.get(server);
if (info != null) { if (info != null) {
info.setLastRequest(System.currentTimeMillis()); info.updateLastRequest();
return info.getOnlinePlayers(); return String.valueOf(info.getOnlinePlayers());
} else { } else {
// It was not tracked, add it. // It was not tracked, add it.
track(server); 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,11 +127,60 @@ public class BungeeServerTracker {
} }
taskID = Bukkit.getScheduler().scheduleSyncRepeatingTask(HolographicDisplays.getInstance(), new Runnable() { taskID = Bukkit.getScheduler().scheduleSyncRepeatingTask(HolographicDisplays.getInstance(), new Runnable() {
@Override
public void run() { public void run() {
if (Configuration.pingerEnable) {
new BukkitRunnable() {
@Override
public void run() {
for (Entry<String, ServerAddress> 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()) { for (String server : trackedServers.keySet()) {
BungeeChannel.getInstance().askPlayerCount(server); BungeeChannel.getInstance().askPlayerCount(server);
} }
} }
}
}, 0, refreshSeconds * 20); }, 0, refreshSeconds * 20);
} }
} }

View File

@ -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) { }
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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 + "]";
}
}

View File

@ -49,9 +49,9 @@ public class ReloadCommand extends HologramSubCommand {
long startMillis = System.currentTimeMillis(); long startMillis = System.currentTimeMillis();
UnicodeSymbols.load(HolographicDisplays.getInstance());
Configuration.load(HolographicDisplays.getInstance()); Configuration.load(HolographicDisplays.getInstance());
BungeeServerTracker.startTask(Configuration.bungeeRefreshSeconds); BungeeServerTracker.startTask(Configuration.bungeeRefreshSeconds);
UnicodeSymbols.load(HolographicDisplays.getInstance());
HologramDatabase.loadYamlFile(HolographicDisplays.getInstance()); HologramDatabase.loadYamlFile(HolographicDisplays.getInstance());
AnimationsRegister.loadAnimations(HolographicDisplays.getInstance()); AnimationsRegister.loadAnimations(HolographicDisplays.getInstance());
PlaceholdersManager.untrackAll(); PlaceholdersManager.untrackAll();

View File

@ -1,5 +1,7 @@
package com.gmail.filoghost.holographicdisplays.disk; package com.gmail.filoghost.holographicdisplays.disk;
import java.util.Arrays;
public enum ConfigNode { public enum ConfigNode {
SPACE_BETWEEN_LINES("space-between-lines", 0.02), SPACE_BETWEEN_LINES("space-between-lines", 0.02),
@ -9,6 +11,12 @@ public enum ConfigNode {
UPDATE_NOTIFICATION("update-notification", true), UPDATE_NOTIFICATION("update-notification", true),
BUNGEE_REFRESH_SECONDS("bungee.refresh-seconds", 3), BUNGEE_REFRESH_SECONDS("bungee.refresh-seconds", 3),
BUNGEE_USE_REDIS_BUNGEE("bungee.use-RedisBungee", false), 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_FORMAT("time.format", "H:mm"),
TIME_ZONE("time.zone", "GMT+1"), TIME_ZONE("time.zone", "GMT+1"),
DEBUG("debug", false); DEBUG("debug", false);

View File

@ -5,6 +5,7 @@ import java.io.IOException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.TimeZone; import java.util.TimeZone;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
@ -12,6 +13,7 @@ import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import com.gmail.filoghost.holographicdisplays.bridge.bungeecord.serverpinger.ServerAddress;
import com.gmail.filoghost.holographicdisplays.util.Utils; import com.gmail.filoghost.holographicdisplays.util.Utils;
/** /**
@ -29,10 +31,15 @@ public class Configuration {
public static SimpleDateFormat timeFormat; public static SimpleDateFormat timeFormat;
public static int bungeeRefreshSeconds; public static int bungeeRefreshSeconds;
public static String bungeeOnlineFormat;
public static String bungeeOfflineFormat;
public static boolean useRedisBungee; public static boolean useRedisBungee;
public static boolean pingerEnable;
public static int pingerTimeout;
public static Map<String, ServerAddress> pingerServers;
public static String pingerOfflineMotd;
public static String pingerStatusOnline;
public static String pingerStatusOffline;
public static boolean debug; public static boolean debug;
@ -112,6 +119,50 @@ public class Configuration {
transparencySymbol = StringConverter.toReadableFormat(config.getString(ConfigNode.TRANSPARENCY_SPACE.getPath())); transparencySymbol = StringConverter.toReadableFormat(config.getString(ConfigNode.TRANSPARENCY_SPACE.getPath()));
bungeeRefreshSeconds = config.getInt(ConfigNode.BUNGEE_REFRESH_SECONDS.getPath()); bungeeRefreshSeconds = config.getInt(ConfigNode.BUNGEE_REFRESH_SECONDS.getPath());
useRedisBungee = config.getBoolean(ConfigNode.BUNGEE_USE_REDIS_BUNGEE.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()); debug = config.getBoolean(ConfigNode.DEBUG.getPath());

View File

@ -23,6 +23,9 @@ public class PlaceholdersManager {
protected static Set<DynamicLineData> linesToUpdate = Utils.newSet(); protected static Set<DynamicLineData> linesToUpdate = Utils.newSet();
private static final Pattern BUNGEE_ONLINE_PATTERN = makePlaceholderWithArgsPattern("online"); 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 ANIMATION_PATTERN = makePlaceholderWithArgsPattern("animation");
private static final Pattern WORLD_PATTERN = makePlaceholderWithArgsPattern("world"); private static final Pattern WORLD_PATTERN = makePlaceholderWithArgsPattern("world");
@ -113,6 +116,10 @@ public class PlaceholdersManager {
Set<Placeholder> normalPlaceholders = null; Set<Placeholder> normalPlaceholders = null;
Map<String, PlaceholderReplacer> bungeeOnlinePlayersReplacers = null; Map<String, PlaceholderReplacer> bungeeOnlinePlayersReplacers = null;
Map<String, PlaceholderReplacer> bungeeMaxPlayersReplacers = null;
Map<String, PlaceholderReplacer> bungeeStatusReplacers = null;
Map<String, PlaceholderReplacer> bungeeMotdReplacers = null;
Map<String, PlaceholderReplacer> worldsOnlinePlayersReplacers = null; Map<String, PlaceholderReplacer> worldsOnlinePlayersReplacers = null;
Map<String, Placeholder> animationsPlaceholders = null; Map<String, Placeholder> animationsPlaceholders = null;
@ -165,11 +172,75 @@ public class PlaceholdersManager {
@Override @Override
public String update() { 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. // Animation pattern.
matcher = ANIMATION_PATTERN.matcher(name); matcher = ANIMATION_PATTERN.matcher(name);
while (matcher.find()) { 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); DynamicLineData lineData = new DynamicLineData(nameableEntity, name);
if (normalPlaceholders != null) { if (normalPlaceholders != null) {
@ -203,6 +275,18 @@ public class PlaceholdersManager {
lineData.getReplacers().putAll(bungeeOnlinePlayersReplacers); 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) { if (worldsOnlinePlayersReplacers != null) {
lineData.getReplacers().putAll(worldsOnlinePlayersReplacers); lineData.getReplacers().putAll(worldsOnlinePlayersReplacers);
} }
@ -236,19 +320,19 @@ public class PlaceholdersManager {
if (!lineData.getPlaceholders().isEmpty()) { if (!lineData.getPlaceholders().isEmpty()) {
for (Placeholder placeholder : lineData.getPlaceholders()) { 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()) { if (!lineData.getReplacers().isEmpty()) {
for (Entry<String, PlaceholderReplacer> entry : lineData.getReplacers().entrySet()) { for (Entry<String, PlaceholderReplacer> 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()) { if (!lineData.getAnimations().isEmpty()) {
for (Entry<String, Placeholder> entry : lineData.getAnimations().entrySet()) { for (Entry<String, Placeholder> entry : lineData.getAnimations().entrySet()) {
newCustomName = newCustomName.replace(entry.getKey(), entry.getValue().getCurrentReplacement()); newCustomName = newCustomName.replace(entry.getKey(), Utils.sanitize(entry.getValue().getCurrentReplacement()));
} }
} }

View File

@ -5,6 +5,7 @@ import java.util.Map.Entry;
import com.gmail.filoghost.holographicdisplays.bridge.bungeecord.BungeeServerInfo; import com.gmail.filoghost.holographicdisplays.bridge.bungeecord.BungeeServerInfo;
import com.gmail.filoghost.holographicdisplays.bridge.bungeecord.BungeeServerTracker; 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. * A task to remove unused server data in the server tracker.
@ -17,11 +18,13 @@ public class BungeeCleanupTask implements Runnable {
Iterator<Entry<String, BungeeServerInfo>> iter = BungeeServerTracker.getTrackedServers().entrySet().iterator(); Iterator<Entry<String, BungeeServerInfo>> iter = BungeeServerTracker.getTrackedServers().entrySet().iterator();
while (iter.hasNext()) { while (iter.hasNext()) {
long lastRequest = iter.next().getValue().getLastRequest(); Entry<String, BungeeServerInfo> next = iter.next();
long lastRequest = next.getValue().getLastRequest();
if (lastRequest != 0 && System.currentTimeMillis() - lastRequest > 600000) { // 10 * 60 * 1000 = 10 minutes. if (lastRequest != 0 && System.currentTimeMillis() - lastRequest > 600000) { // 10 * 60 * 1000 = 10 minutes.
// Don't track that server anymore. // Don't track that server anymore.
iter.remove(); iter.remove();
DebugHandler.logToConsole("Untracked bungee server \"" + next.getKey() + "\" due to inactivity.");
} }
} }
} }

View File

@ -6,15 +6,25 @@ import com.gmail.filoghost.holographicdisplays.disk.Configuration;
public class DebugHandler { public class DebugHandler {
public static void handleSpawnFail(HologramLine parentPiece) { public static void logToConsole(String msg) {
if (Configuration.debug) { 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) { public static void handleAnimationLoadSuccess(String name, double speed) {
logToConsole("Successfully loaded animation '" + name + "', speed = " + speed + ".");
}
public static void handleSpawnFail(HologramLine parentPiece) {
if (Configuration.debug) { 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();
} }
} }

View File

@ -106,4 +106,22 @@ public class Utils extends Object {
public static String join(List<String> elements, String separator) { public static String join(List<String> elements, String separator) {
return join(elements, separator, 0, elements.size()); 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;
}
} }