From 2c1d7b34e6bf5f8a0810e02b0b4e542e526370c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sundahl?= Date: Sun, 28 Oct 2012 02:05:08 +0200 Subject: [PATCH] Fix issue #7 by adding Tab List Support. Thanks @ranzdo --- src/main/java/net/md_5/bungee/BungeeCord.java | 35 ++++++++++ .../java/net/md_5/bungee/Configuration.java | 7 ++ .../java/net/md_5/bungee/UserConnection.java | 42 +++++++++++ .../md_5/bungee/packet/Packet0KeepAlive.java | 18 +++++ .../bungee/packet/PacketC9PlayerListItem.java | 30 ++++++++ .../bungee/plugin/ServerConnectEvent.java | 3 +- .../bungee/tablist/GlobalPingTabList.java | 28 ++++++++ .../md_5/bungee/tablist/GlobalTabList.java | 52 ++++++++++++++ .../bungee/tablist/ServerUnqiueTabList.java | 70 +++++++++++++++++++ .../md_5/bungee/tablist/TabListHandler.java | 18 +++++ 10 files changed, 301 insertions(+), 2 deletions(-) create mode 100644 src/main/java/net/md_5/bungee/packet/Packet0KeepAlive.java create mode 100644 src/main/java/net/md_5/bungee/packet/PacketC9PlayerListItem.java create mode 100644 src/main/java/net/md_5/bungee/tablist/GlobalPingTabList.java create mode 100644 src/main/java/net/md_5/bungee/tablist/GlobalTabList.java create mode 100644 src/main/java/net/md_5/bungee/tablist/ServerUnqiueTabList.java create mode 100644 src/main/java/net/md_5/bungee/tablist/TabListHandler.java diff --git a/src/main/java/net/md_5/bungee/BungeeCord.java b/src/main/java/net/md_5/bungee/BungeeCord.java index f1088f4b..917b3156 100644 --- a/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/src/main/java/net/md_5/bungee/BungeeCord.java @@ -22,7 +22,12 @@ import net.md_5.bungee.command.CommandMotd; import net.md_5.bungee.command.CommandSender; import net.md_5.bungee.command.CommandServer; import net.md_5.bungee.command.ConsoleCommandSender; +import net.md_5.bungee.packet.DefinedPacket; import net.md_5.bungee.plugin.JavaPluginManager; +import net.md_5.bungee.tablist.GlobalPingTabList; +import net.md_5.bungee.tablist.GlobalTabList; +import net.md_5.bungee.tablist.ServerUnqiueTabList; +import net.md_5.bungee.tablist.TabListHandler; /** * Main BungeeCord proxy class. @@ -66,6 +71,10 @@ public class BungeeCord * Registered commands. */ public Map commandMap = new HashMap<>(); + /** + * Tab list handler + */ + public TabListHandler tabListHandler; /** * Plugin manager. */ @@ -154,6 +163,19 @@ public class BungeeCord pluginManager.loadPlugins(); + switch (config.tabList) + { + case 1: + tabListHandler = new GlobalPingTabList(); + break; + case 2: + tabListHandler = new GlobalTabList(); + break; + case 3: + tabListHandler = new ServerUnqiueTabList(); + break; + } + InetSocketAddress addr = Util.getAddr(config.bindHost); listener = new ListenThread(addr); listener.start(); @@ -219,4 +241,17 @@ public class BungeeCord socket.setTrafficClass(0x18); socket.setTcpNoDelay(true); } + + /** + * Broadcasts a packet to all clients that is connected to this instance. + * + * @param packet the packet to send + */ + public void broadcast(DefinedPacket packet) + { + for (UserConnection con : connections.values()) + { + con.packetQueue.add(packet); + } + } } diff --git a/src/main/java/net/md_5/bungee/Configuration.java b/src/main/java/net/md_5/bungee/Configuration.java index 2bf7c0a7..7f1bf1c4 100644 --- a/src/main/java/net/md_5/bungee/Configuration.java +++ b/src/main/java/net/md_5/bungee/Configuration.java @@ -70,6 +70,13 @@ public class Configuration * Max players as displayed in list ping. Soft limit. */ public int maxPlayers = 1; + /** + * Tab list 1: For a tab list that is global over all server (using their + * minecraft name) and updating their ping frequently 2: Same as 1 but does + * not update their ping frequently, just once. 3: Makes the individual + * servers handle the tab list (server unique) + */ + public int tabList = 1; /** * Socket timeout. */ diff --git a/src/main/java/net/md_5/bungee/UserConnection.java b/src/main/java/net/md_5/bungee/UserConnection.java index 95495042..ab610a5b 100644 --- a/src/main/java/net/md_5/bungee/UserConnection.java +++ b/src/main/java/net/md_5/bungee/UserConnection.java @@ -9,10 +9,12 @@ import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import net.md_5.bungee.command.CommandSender; import net.md_5.bungee.packet.DefinedPacket; +import net.md_5.bungee.packet.Packet0KeepAlive; import net.md_5.bungee.packet.Packet1Login; import net.md_5.bungee.packet.Packet2Handshake; import net.md_5.bungee.packet.Packet3Chat; import net.md_5.bungee.packet.Packet9Respawn; +import net.md_5.bungee.packet.PacketC9PlayerListItem; import net.md_5.bungee.packet.PacketFAPluginMessage; import net.md_5.bungee.packet.PacketInputStream; import net.md_5.bungee.plugin.ServerConnectEvent; @@ -29,6 +31,10 @@ public class UserConnection extends GenericConnection implements CommandSender private int clientEntityId; private int serverEntityId; private volatile boolean reconnecting; + // ping stuff + private int trackingPingId; + private long pingTime; + private int ping; public UserConnection(Socket socket, PacketInputStream in, OutputStream out, Packet2Handshake handshake) { @@ -36,6 +42,7 @@ public class UserConnection extends GenericConnection implements CommandSender this.handshake = handshake; username = handshake.username; BungeeCord.instance.connections.put(username, this); + BungeeCord.instance.tabListHandler.onJoin(this); } public void connect(String server) @@ -63,6 +70,7 @@ public class UserConnection extends GenericConnection implements CommandSender private void connect(String name, InetSocketAddress serverAddr) { + BungeeCord.instance.tabListHandler.onServerChange(this); try { reconnecting = true; @@ -115,6 +123,17 @@ public class UserConnection extends GenericConnection implements CommandSender return socket.getRemoteSocketAddress(); } + public int getPing() + { + return ping; + } + + private void setPing(int ping) + { + BungeeCord.instance.tabListHandler.onPingChange(this, ping); + this.ping = ping; + } + private void destroySelf(String reason) { if (BungeeCord.instance.isRunning) @@ -129,6 +148,13 @@ public class UserConnection extends GenericConnection implements CommandSender } } + @Override + public void disconnect(String reason) + { + BungeeCord.instance.tabListHandler.onDisconnect(this); + super.disconnect(reason); + } + @Override public void sendMessage(String message) { @@ -168,6 +194,12 @@ public class UserConnection extends GenericConnection implements CommandSender { sendPacket = !BungeeCord.instance.dispatchCommand(message.substring(1), UserConnection.this); } + } else if (id == 0x00) + { + if (trackingPingId == new Packet0KeepAlive(packet).id) + { + setPing((int) (System.currentTimeMillis() - pingTime)); + } } EntityMap.rewrite(packet, clientEntityId, serverEntityId); @@ -213,6 +245,16 @@ public class UserConnection extends GenericConnection implements CommandSender connect(server); break; } + } else if (id == 0x00) + { + trackingPingId = new Packet0KeepAlive(packet).id; + pingTime = System.currentTimeMillis(); + } else if (id == 0xC9) + { + if (!BungeeCord.instance.tabListHandler.onPacketC9(UserConnection.this, new PacketC9PlayerListItem(packet))) + { + continue; + } } while (!packetQueue.isEmpty()) diff --git a/src/main/java/net/md_5/bungee/packet/Packet0KeepAlive.java b/src/main/java/net/md_5/bungee/packet/Packet0KeepAlive.java new file mode 100644 index 00000000..8355694e --- /dev/null +++ b/src/main/java/net/md_5/bungee/packet/Packet0KeepAlive.java @@ -0,0 +1,18 @@ +package net.md_5.bungee.packet; + +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@ToString +@EqualsAndHashCode(callSuper = false) +public class Packet0KeepAlive extends DefinedPacket +{ + + public int id; + + public Packet0KeepAlive(byte[] buffer) + { + super(0x00, buffer); + id = readInt(); + } +} diff --git a/src/main/java/net/md_5/bungee/packet/PacketC9PlayerListItem.java b/src/main/java/net/md_5/bungee/packet/PacketC9PlayerListItem.java new file mode 100644 index 00000000..b0f76fdb --- /dev/null +++ b/src/main/java/net/md_5/bungee/packet/PacketC9PlayerListItem.java @@ -0,0 +1,30 @@ +package net.md_5.bungee.packet; + +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@ToString +@EqualsAndHashCode(callSuper = false) +public class PacketC9PlayerListItem extends DefinedPacket +{ + + public String username; + public boolean online; + public int ping; + + public PacketC9PlayerListItem(byte[] packet) + { + super(0xC9, packet); + username = readUTF(); + online = readBoolean(); + ping = readShort(); + } + + public PacketC9PlayerListItem(String username, boolean online, int ping) + { + super(0xC9); + writeUTF(username); + writeBoolean(online); + writeShort(ping); + } +} diff --git a/src/main/java/net/md_5/bungee/plugin/ServerConnectEvent.java b/src/main/java/net/md_5/bungee/plugin/ServerConnectEvent.java index 7b6a7784..6a7339bb 100644 --- a/src/main/java/net/md_5/bungee/plugin/ServerConnectEvent.java +++ b/src/main/java/net/md_5/bungee/plugin/ServerConnectEvent.java @@ -15,8 +15,7 @@ public class ServerConnectEvent */ private final boolean firstTime; /** - * Message to send just before the change. - * null for no message + * Message to send just before the change. null for no message */ private String message; /** diff --git a/src/main/java/net/md_5/bungee/tablist/GlobalPingTabList.java b/src/main/java/net/md_5/bungee/tablist/GlobalPingTabList.java new file mode 100644 index 00000000..e6ac5ec5 --- /dev/null +++ b/src/main/java/net/md_5/bungee/tablist/GlobalPingTabList.java @@ -0,0 +1,28 @@ +package net.md_5.bungee.tablist; + +import java.util.Collections; +import java.util.Map; +import java.util.WeakHashMap; + +import net.md_5.bungee.BungeeCord; +import net.md_5.bungee.UserConnection; +import net.md_5.bungee.packet.PacketC9PlayerListItem; + +public class GlobalPingTabList extends GlobalTabList +{ + + public static final int PING_THRESHOLD = 20; + private Map lastPings = + Collections.synchronizedMap(new WeakHashMap()); + + @Override + public void onPingChange(final UserConnection con, final int ping) + { + Integer lastPing = lastPings.get(con); + if (lastPing == null || (ping - PING_THRESHOLD > lastPing && ping + PING_THRESHOLD < lastPing)) + { + BungeeCord.instance.broadcast(new PacketC9PlayerListItem(con.username, true, ping)); + lastPings.put(con, ping); + } + } +} diff --git a/src/main/java/net/md_5/bungee/tablist/GlobalTabList.java b/src/main/java/net/md_5/bungee/tablist/GlobalTabList.java new file mode 100644 index 00000000..524db3aa --- /dev/null +++ b/src/main/java/net/md_5/bungee/tablist/GlobalTabList.java @@ -0,0 +1,52 @@ +package net.md_5.bungee.tablist; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import net.md_5.bungee.BungeeCord; +import net.md_5.bungee.UserConnection; +import net.md_5.bungee.packet.PacketC9PlayerListItem; + +public class GlobalTabList implements TabListHandler +{ + + private Set sentPings = Collections.synchronizedSet(new HashSet()); + + @Override + public void onJoin(UserConnection con) + { + for (UserConnection con2 : BungeeCord.instance.connections.values()) + { + con.packetQueue.add(new PacketC9PlayerListItem(con2.username, true, con2.getPing())); + } + } + + @Override + public void onServerChange(UserConnection con) + { + } + + @Override + public void onPingChange(final UserConnection con, final int ping) + { + if (!sentPings.contains(con)) + { + BungeeCord.instance.broadcast(new PacketC9PlayerListItem(con.username, true, con.getPing())); + sentPings.add(con); + } + } + + @Override + public void onDisconnect(final UserConnection con) + { + BungeeCord.instance.broadcast(new PacketC9PlayerListItem(con.username, false, 9999)); + sentPings.remove(con); + } + + @Override + public boolean onPacketC9(UserConnection con, PacketC9PlayerListItem packet) + { + return false; + } +} diff --git a/src/main/java/net/md_5/bungee/tablist/ServerUnqiueTabList.java b/src/main/java/net/md_5/bungee/tablist/ServerUnqiueTabList.java new file mode 100644 index 00000000..86ba66d8 --- /dev/null +++ b/src/main/java/net/md_5/bungee/tablist/ServerUnqiueTabList.java @@ -0,0 +1,70 @@ +package net.md_5.bungee.tablist; + +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; + +import net.md_5.bungee.UserConnection; +import net.md_5.bungee.packet.PacketC9PlayerListItem; + +public class ServerUnqiueTabList implements TabListHandler +{ + + private Map> sentUsernames = + Collections.synchronizedMap(new WeakHashMap>()); + + @Override + public void onJoin(UserConnection con) + { + } + + @Override + public void onServerChange(UserConnection con) + { + Set usernames = sentUsernames.get(con); + synchronized (usernames) + { + if (usernames != null) + { + for (String username : usernames) + { + con.packetQueue.add(new PacketC9PlayerListItem(username, false, 9999)); + } + } + usernames.clear(); + } + } + + @Override + public void onPingChange(UserConnection con, int ping) + { + } + + @Override + public void onDisconnect(UserConnection con) + { + } + + @Override + public boolean onPacketC9(final UserConnection con, final PacketC9PlayerListItem packet) + { + Set usernames = sentUsernames.get(con); + if (usernames == null) + { + usernames = new LinkedHashSet<>(); + sentUsernames.put(con, usernames); + } + + if (packet.online) + { + usernames.add(packet.username); + } else + { + usernames.remove(packet.username); + } + + return true; + } +} diff --git a/src/main/java/net/md_5/bungee/tablist/TabListHandler.java b/src/main/java/net/md_5/bungee/tablist/TabListHandler.java new file mode 100644 index 00000000..b11d92e7 --- /dev/null +++ b/src/main/java/net/md_5/bungee/tablist/TabListHandler.java @@ -0,0 +1,18 @@ +package net.md_5.bungee.tablist; + +import net.md_5.bungee.UserConnection; +import net.md_5.bungee.packet.PacketC9PlayerListItem; + +public interface TabListHandler +{ + + public void onJoin(UserConnection con); + + public void onServerChange(UserConnection con); + + public void onPingChange(UserConnection con, int ping); + + public void onDisconnect(UserConnection con); + + public boolean onPacketC9(UserConnection con, PacketC9PlayerListItem packet); +}