Fix issue #7 by adding Tab List Support. Thanks @ranzdo

This commit is contained in:
Björn Sundahl 2012-10-28 02:05:08 +02:00 committed by md_5
parent e4522c7ab4
commit 2c1d7b34e6
10 changed files with 301 additions and 2 deletions

View File

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

View File

@ -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.
*/

View File

@ -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())

View File

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

View File

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

View File

@ -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;
/**

View File

@ -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<UserConnection, Integer> lastPings =
Collections.synchronizedMap(new WeakHashMap<UserConnection, Integer>());
@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);
}
}
}

View File

@ -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<UserConnection> sentPings = Collections.synchronizedSet(new HashSet<UserConnection>());
@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;
}
}

View File

@ -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<UserConnection, Set<String>> sentUsernames =
Collections.synchronizedMap(new WeakHashMap<UserConnection, Set<String>>());
@Override
public void onJoin(UserConnection con)
{
}
@Override
public void onServerChange(UserConnection con)
{
Set<String> 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<String> 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;
}
}

View File

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