This is hard >.>

This commit is contained in:
md_5 2013-01-18 10:46:55 +11:00
parent 55867dbdc3
commit 32ef5212f8
7 changed files with 93 additions and 132 deletions

View File

@ -113,6 +113,20 @@ public abstract class ProxyServer
*/ */
public abstract void setTabListHandler(TabListHandler handler); public abstract void setTabListHandler(TabListHandler handler);
/**
* Get the currently in use reconnect handler.
*
* @return the in use reconnect handler
*/
public abstract ReconnectHandler getReconnectHandler();
/**
* Sets the reconnect handler to be used for subsequent connections.
*
* @param handler the new handler
*/
public abstract void setReconnectHandler(ReconnectHandler handler);
/** /**
* Gracefully mark this instance for shutdown. * Gracefully mark this instance for shutdown.
*/ */

View File

@ -28,4 +28,12 @@ public interface PendingConnection extends Connection
* @return request virtual host or null if invalid / not specified. * @return request virtual host or null if invalid / not specified.
*/ */
public InetSocketAddress getVirtualHost(); public InetSocketAddress getVirtualHost();
/**
* Completely kick this user from the proxy and all of its child
* connections.
*
* @param reason the disconnect reason displayed to the player
*/
public void disconnect(String reason);
} }

View File

@ -49,14 +49,6 @@ public interface ProxiedPlayer extends Connection, CommandSender
*/ */
public int getPing(); public int getPing();
/**
* Completely kick this user from the proxy and all of its child
* connections.
*
* @param reason the disconnect reason displayed to the player
*/
public void disconnect(String reason);
/** /**
* Send a plugin message to this player. * Send a plugin message to this player.
* *

View File

@ -9,24 +9,26 @@ import java.net.Socket;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Queue;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger; import java.util.logging.Logger;
import lombok.Getter; import lombok.Getter;
import lombok.Setter;
import static net.md_5.bungee.Logger.$; import static net.md_5.bungee.Logger.$;
import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.ReconnectHandler;
import net.md_5.bungee.api.TabListHandler; import net.md_5.bungee.api.TabListHandler;
import net.md_5.bungee.api.config.ConfigurationAdapter; import net.md_5.bungee.api.config.ConfigurationAdapter;
import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.connection.Server; import net.md_5.bungee.api.connection.Server;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.api.plugin.PluginManager; import net.md_5.bungee.api.plugin.PluginManager;
import net.md_5.bungee.command.*; import net.md_5.bungee.command.*;
import net.md_5.bungee.packet.DefinedPacket; import net.md_5.bungee.packet.DefinedPacket;
import net.md_5.bungee.packet.PacketFAPluginMessage;
import net.md_5.bungee.tablist.GlobalPingTabList; import net.md_5.bungee.tablist.GlobalPingTabList;
import net.md_5.bungee.tablist.GlobalTabList; import net.md_5.bungee.tablist.GlobalTabList;
import net.md_5.bungee.tablist.ServerUniqueTabList; import net.md_5.bungee.tablist.ServerUniqueTabList;
@ -65,10 +67,6 @@ public class BungeeCord extends ProxyServer
* Server socket listener. * Server socket listener.
*/ */
private ListenThread listener; private ListenThread listener;
/**
* Current version.
*/
public static String version = (BungeeCord.class.getPackage().getImplementationVersion() == null) ? "unknown" : BungeeCord.class.getPackage().getImplementationVersion();
/** /**
* Fully qualified connections. * Fully qualified connections.
*/ */
@ -77,16 +75,17 @@ public class BungeeCord extends ProxyServer
/** /**
* Tab list handler * Tab list handler
*/ */
@Getter
@Setter
public TabListHandler tabListHandler; public TabListHandler tabListHandler;
/**
* Registered Global Plugin Channels
*/
public Queue<String> globalPluginChannels = new ConcurrentLinkedQueue<>();
/** /**
* Plugin manager. * Plugin manager.
*/ */
@Getter @Getter
public final PluginManager pluginManager = new PluginManager(); public final PluginManager pluginManager = new PluginManager();
@Getter
@Setter
private ReconnectHandler reconnectHandler;
{ {
@ -163,14 +162,18 @@ public class BungeeCord extends ProxyServer
break; break;
} }
// Add RubberBand to the global plugin channel list
globalPluginChannels.add("RubberBand");
InetSocketAddress addr = Util.getAddr(config.bindHost); InetSocketAddress addr = Util.getAddr(config.bindHost);
listener = new ListenThread(addr); listener = new ListenThread(addr);
listener.start(); listener.start();
saveThread.start(); saveThread.scheduleAtFixedRate(new TimerTask()
{
@Override
public void run()
{
getReconnectHandler().save();
}
}, 0, TimeUnit.MINUTES.toMillis(5));
$().info("Listening on " + addr); $().info("Listening on " + addr);
if (config.metricsEnabled) if (config.metricsEnabled)
@ -186,8 +189,11 @@ public class BungeeCord extends ProxyServer
public void stop() public void stop()
{ {
this.isRunning = false; this.isRunning = false;
$().info("Disabling plugin"); $().info("Disabling plugins");
pluginManager.onDisable(); for (Plugin plugin : pluginManager.getPlugins())
{
plugin.onDisable();
}
$().info("Closing listen thread"); $().info("Closing listen thread");
try try
@ -209,13 +215,7 @@ public class BungeeCord extends ProxyServer
} }
$().info("Saving reconnect locations"); $().info("Saving reconnect locations");
saveThread.interrupt(); saveThread.cancel();
try
{
saveThread.join();
} catch (InterruptedException ex)
{
}
$().info("Thank you and goodbye"); $().info("Thank you and goodbye");
System.exit(0); System.exit(0);
@ -248,71 +248,6 @@ public class BungeeCord extends ProxyServer
} }
} }
/**
* Broadcasts a plugin message to all servers with currently connected
* players.
*
* @param channel name
* @param message to send
*/
public void broadcastPluginMessage(String channel, String message)
{
broadcastPluginMessage(channel, message, null);
}
/**
* Broadcasts a plugin message to all servers with currently connected
* players.
*
* @param channel name
* @param message to send
* @param server the message was sent from originally
*/
public void broadcastPluginMessage(String channel, String message, String sourceServer)
{
for (String server : connectionsByServer.keySet())
{
if (sourceServer == null || !sourceServer.equals(server))
{
List<UserConnection> conns = BungeeCord.instance.connectionsByServer.get(server);
if (conns != null && conns.size() > 0)
{
UserConnection user = conns.get(0);
user.sendPluginMessage(channel, message.getBytes());
}
}
}
}
/**
* Send a plugin message to a specific server if it has currently connected
* players.
*
* @param channel name
* @param message to send
* @param server the message is to be sent to
*/
public void sendPluginMessage(String channel, String message, String targetServer)
{
List<UserConnection> conns = connectionsByServer.get(targetServer);
if (conns != null && conns.size() > 0)
{
UserConnection user = conns.get(0);
user.sendPluginMessage(channel, message.getBytes());
}
}
/**
* Register a plugin channel for all users
*
* @param channel name
*/
public void registerPluginChannel(String channel)
{
globalPluginChannels.add(channel);
broadcast(new PacketFAPluginMessage("REGISTER", channel.getBytes()));
}
@Override @Override
public String getName() public String getName()
{ {
@ -322,7 +257,7 @@ public class BungeeCord extends ProxyServer
@Override @Override
public String getVersion() public String getVersion()
{ {
return version; return (BungeeCord.class.getPackage().getImplementationVersion() == null) ? "unknown" : BungeeCord.class.getPackage().getImplementationVersion();
} }
@Override @Override
@ -332,15 +267,16 @@ public class BungeeCord extends ProxyServer
} }
@Override @Override
@SuppressWarnings("unchecked") // TODO: Abstract more
public Collection<ProxiedPlayer> getPlayers() public Collection<ProxiedPlayer> getPlayers()
{ {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. return (Collection) connections.values();
} }
@Override @Override
public ProxiedPlayer getPlayer(String name) public ProxiedPlayer getPlayer(String name)
{ {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. return connections.get(name);
} }
@Override @Override

View File

@ -2,26 +2,30 @@ package net.md_5.bungee;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket; import java.net.Socket;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.event.LoginEvent;
import net.md_5.bungee.packet.Packet2Handshake; import net.md_5.bungee.packet.Packet2Handshake;
import net.md_5.bungee.packet.PacketFCEncryptionResponse; import net.md_5.bungee.packet.PacketFCEncryptionResponse;
import net.md_5.bungee.packet.PacketFDEncryptionRequest; import net.md_5.bungee.packet.PacketFDEncryptionRequest;
import net.md_5.bungee.packet.PacketFFKick; import net.md_5.bungee.packet.PacketFFKick;
import net.md_5.bungee.packet.PacketInputStream; import net.md_5.bungee.packet.PacketInputStream;
import net.md_5.bungee.plugin.LoginEvent;
import org.bouncycastle.crypto.io.CipherInputStream; import org.bouncycastle.crypto.io.CipherInputStream;
import org.bouncycastle.crypto.io.CipherOutputStream; import org.bouncycastle.crypto.io.CipherOutputStream;
public class InitialHandler implements Runnable public class InitialHandler implements Runnable, PendingConnection
{ {
private final Socket socket; private final Socket socket;
private PacketInputStream in; private PacketInputStream in;
private OutputStream out; private OutputStream out;
private Packet2Handshake handshake;
public InitialHandler(Socket socket) throws IOException public InitialHandler(Socket socket) throws IOException
{ {
@ -40,15 +44,7 @@ public class InitialHandler implements Runnable
switch (id) switch (id)
{ {
case 0x02: case 0x02:
Packet2Handshake handshake = new Packet2Handshake(packet); handshake = new Packet2Handshake(packet);
// fire connect event
LoginEvent event = new LoginEvent(handshake.username, socket.getInetAddress(), handshake.host);
BungeeCord.instance.pluginManager.onHandshake(event);
if (event.isCancelled())
{
throw new KickException(event.getCancelReason());
}
PacketFDEncryptionRequest request = EncryptionUtil.encryptRequest(); PacketFDEncryptionRequest request = EncryptionUtil.encryptRequest();
out.write(request.getPacket()); out.write(request.getPacket());
PacketFCEncryptionResponse response = new PacketFCEncryptionResponse(in.readPacket()); PacketFCEncryptionResponse response = new PacketFCEncryptionResponse(in.readPacket());
@ -59,8 +55,8 @@ public class InitialHandler implements Runnable
throw new KickException("Not authenticated with minecraft.net"); throw new KickException("Not authenticated with minecraft.net");
} }
// fire post auth event // fire login event
BungeeCord.instance.pluginManager.onLogin(event); LoginEvent event = new LoginEvent(this);
if (event.isCancelled()) if (event.isCancelled())
{ {
throw new KickException(event.getCancelReason()); throw new KickException(event.getCancelReason());
@ -77,8 +73,6 @@ public class InitialHandler implements Runnable
} }
UserConnection userCon = new UserConnection(socket, in, out, handshake, customPackets); UserConnection userCon = new UserConnection(socket, in, out, handshake, customPackets);
String server = (BungeeCord.instance.config.forceDefaultServer) ? BungeeCord.instance.config.defaultServerName : BungeeCord.instance.config.getServer(handshake.username, handshake.host);
userCon.connect(server);
break; break;
case 0xFE: case 0xFE:
socket.setSoTimeout(100); socket.setSoTimeout(100);
@ -90,14 +84,14 @@ public class InitialHandler implements Runnable
} catch (IOException ex) } catch (IOException ex)
{ {
} }
Configuration conf = BungeeCord.instance.config; Configuration conf = BungeeCord.getInstance().config;
String ping = (newPing) ? ChatColor.COLOR_CHAR + "1" String ping = (newPing) ? ChatColor.COLOR_CHAR + "1"
+ "\00" + BungeeCord.PROTOCOL_VERSION + "\00" + BungeeCord.PROTOCOL_VERSION
+ "\00" + BungeeCord.GAME_VERSION + "\00" + BungeeCord.GAME_VERSION
+ "\00" + conf.motd + "\00" + conf.motd
+ "\00" + BungeeCord.instance.connections.size() + "\00" + ProxyServer.getInstance().getPlayers().size()
+ "\00" + conf.maxPlayers + "\00" + conf.maxPlayers
: conf.motd + ChatColor.COLOR_CHAR + BungeeCord.instance.connections.size() + ChatColor.COLOR_CHAR + conf.maxPlayers; : conf.motd + ChatColor.COLOR_CHAR + ProxyServer.getInstance().getPlayers().size() + ChatColor.COLOR_CHAR + conf.maxPlayers;
throw new KickException(ping); throw new KickException(ping);
default: default:
if (id == 0xFA) if (id == 0xFA)
@ -110,18 +104,19 @@ public class InitialHandler implements Runnable
} }
} catch (KickException ex) } catch (KickException ex)
{ {
kick(ex.getMessage()); disconnect(ex.getMessage());
} catch (Exception ex) } catch (Exception ex)
{ {
kick("[Proxy Error] " + Util.exception(ex)); disconnect("[Proxy Error] " + Util.exception(ex));
} }
} }
private void kick(String message) @Override
public void disconnect(String reason)
{ {
try try
{ {
out.write(new PacketFFKick(message).getPacket()); out.write(new PacketFFKick(reason).getPacket());
} catch (IOException ioe) } catch (IOException ioe)
{ {
} finally } finally
@ -135,4 +130,28 @@ public class InitialHandler implements Runnable
} }
} }
} }
@Override
public String getName()
{
return (handshake == null) ? null : handshake.username;
}
@Override
public byte getVersion()
{
return (handshake == null) ? -1 : handshake.procolVersion;
}
@Override
public InetSocketAddress getVirtualHost()
{
return (handshake == null) ? null : new InetSocketAddress(handshake.host, handshake.port);
}
@Override
public InetSocketAddress getAddress()
{
return (InetSocketAddress) socket.getRemoteSocketAddress();
}
} }

View File

@ -17,7 +17,6 @@ import net.md_5.bungee.packet.DefinedPacket;
import net.md_5.bungee.packet.Packet1Login; import net.md_5.bungee.packet.Packet1Login;
import net.md_5.bungee.packet.Packet2Handshake; import net.md_5.bungee.packet.Packet2Handshake;
import net.md_5.bungee.packet.PacketCDClientStatus; import net.md_5.bungee.packet.PacketCDClientStatus;
import net.md_5.bungee.packet.PacketFAPluginMessage;
import net.md_5.bungee.packet.PacketFCEncryptionResponse; import net.md_5.bungee.packet.PacketFCEncryptionResponse;
import net.md_5.bungee.packet.PacketFDEncryptionRequest; import net.md_5.bungee.packet.PacketFDEncryptionRequest;
import net.md_5.bungee.packet.PacketFFKick; import net.md_5.bungee.packet.PacketFFKick;
@ -84,13 +83,6 @@ public class ServerConnection extends GenericConnection implements Server
} }
Packet1Login login = new Packet1Login(loginResponse); Packet1Login login = new Packet1Login(loginResponse);
// Register all global plugin message channels
// TODO: Allow player-specific plugin message channels for full mod support
for (String channel : BungeeCord.getInstance().globalPluginChannels)
{
out.write(new PacketFAPluginMessage("REGISTER", channel.getBytes()).getPacket());
}
return new ServerConnection(name, socket, in, out, login); return new ServerConnection(name, socket, in, out, login);
} catch (KickException ex) } catch (KickException ex)
{ {

View File

@ -1,8 +1,8 @@
package net.md_5.bungee.command; package net.md_5.bungee.command;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.plugin.Command; import net.md_5.bungee.api.plugin.Command;
public class CommandBungee extends Command public class CommandBungee extends Command
@ -16,6 +16,6 @@ public class CommandBungee extends Command
@Override @Override
public void execute(CommandSender sender, String[] args) public void execute(CommandSender sender, String[] args)
{ {
sender.sendMessage(ChatColor.BLUE + "This server is running BungeeCord version " + BungeeCord.version + " by md_5"); sender.sendMessage(ChatColor.BLUE + "This server is running BungeeCord version " + ProxyServer.getInstance().getVersion() + " by md_5");
} }
} }