A ton of javadocs and small fixes in preparation for rewriting bridge system and eventual release.
This commit is contained in:
parent
c6749726c5
commit
aa2710c573
@ -11,6 +11,7 @@ import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.logging.Level;
|
||||
import static net.md_5.bungee.Logger.$;
|
||||
import net.md_5.bungee.command.Command;
|
||||
import net.md_5.bungee.command.CommandEnd;
|
||||
@ -20,6 +21,9 @@ import net.md_5.bungee.command.CommandServer;
|
||||
import net.md_5.bungee.command.ConsoleCommandSender;
|
||||
import net.md_5.bungee.plugin.JavaPluginManager;
|
||||
|
||||
/**
|
||||
* Main BungeeCord proxy class.
|
||||
*/
|
||||
public class BungeeCord {
|
||||
|
||||
/**
|
||||
@ -69,6 +73,12 @@ public class BungeeCord {
|
||||
commandMap.put("server", new CommandServer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new instance of BungeeCord.
|
||||
*
|
||||
* @param args command line arguments, currently none are used
|
||||
* @throws IOException when the server cannot be started
|
||||
*/
|
||||
public static void main(String[] args) throws IOException {
|
||||
instance = new BungeeCord();
|
||||
$().info("Enabled BungeeCord version " + instance.version);
|
||||
@ -86,26 +96,38 @@ public class BungeeCord {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a command by formatting the arguments and then executing it.
|
||||
*
|
||||
* @param commandLine the entire command and arguments string
|
||||
* @param sender which executed the command
|
||||
* @return whether the command was handled or not.
|
||||
*/
|
||||
public boolean dispatchCommand(String commandLine, CommandSender sender) {
|
||||
String[] split = commandLine.trim().split(" ");
|
||||
String commandName = split[0].toLowerCase();
|
||||
if (commandMap.containsKey(commandName)) {
|
||||
Command command = commandMap.get(commandName);
|
||||
if (command != null) {
|
||||
String[] args = Arrays.copyOfRange(split, 1, split.length);
|
||||
Command c = commandMap.get(commandName);
|
||||
try {
|
||||
c.execute(sender, args);
|
||||
command.execute(sender, args);
|
||||
} catch (Exception ex) {
|
||||
sender.sendMessage(ChatColor.RED + "An error occurred while executing this command!");
|
||||
System.err.println("----------------------- [Start of command error] -----------------------");
|
||||
ex.printStackTrace();
|
||||
System.err.println("----------------------- [End of command error] -----------------------");
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
$().severe("----------------------- [Start of command error] -----------------------");
|
||||
$().log(Level.SEVERE, "", ex);
|
||||
$().severe("----------------------- [End of command error] -----------------------");
|
||||
}
|
||||
}
|
||||
|
||||
return command != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start this proxy instance by loading the configuration, plugins and
|
||||
* starting the connect thread.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void start() throws IOException {
|
||||
config.load();
|
||||
isRunning = true;
|
||||
@ -120,6 +142,10 @@ public class BungeeCord {
|
||||
$().info("Listening on " + addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy this proxy instance cleanly by kicking all users, saving the
|
||||
* configuration and closing all sockets.
|
||||
*/
|
||||
public void stop() {
|
||||
this.isRunning = false;
|
||||
$().info("Disabling plugin");
|
||||
@ -151,6 +177,13 @@ public class BungeeCord {
|
||||
$().info("Thank you and goodbye");
|
||||
}
|
||||
|
||||
/**
|
||||
* Miscellaneous method to set options on a socket based on those in the
|
||||
* configuration.
|
||||
*
|
||||
* @param socket to set the options on
|
||||
* @throws IOException when the underlying set methods thrown an exception
|
||||
*/
|
||||
public void setSocketOptions(Socket socket) throws IOException {
|
||||
socket.setSoTimeout(config.timeout);
|
||||
socket.setTrafficClass(0x18);
|
||||
|
@ -1,133 +1,116 @@
|
||||
package net.md_5.bungee;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* All supported color values for chat
|
||||
* Simplistic enumeration of all supported color values for chat.
|
||||
*/
|
||||
public enum ChatColor {
|
||||
|
||||
/**
|
||||
* Represents black
|
||||
* Represents black.
|
||||
*/
|
||||
BLACK('0', 0x00),
|
||||
BLACK('0'),
|
||||
/**
|
||||
* Represents dark blue
|
||||
* Represents dark blue.
|
||||
*/
|
||||
DARK_BLUE('1', 0x1),
|
||||
DARK_BLUE('1'),
|
||||
/**
|
||||
* Represents dark green
|
||||
* Represents dark green.
|
||||
*/
|
||||
DARK_GREEN('2', 0x2),
|
||||
DARK_GREEN('2'),
|
||||
/**
|
||||
* Represents dark blue (aqua)
|
||||
* Represents dark blue (aqua).
|
||||
*/
|
||||
DARK_AQUA('3', 0x3),
|
||||
DARK_AQUA('3'),
|
||||
/**
|
||||
* Represents dark red
|
||||
* Represents dark red.
|
||||
*/
|
||||
DARK_RED('4', 0x4),
|
||||
DARK_RED('4'),
|
||||
/**
|
||||
* Represents dark purple
|
||||
* Represents dark purple.
|
||||
*/
|
||||
DARK_PURPLE('5', 0x5),
|
||||
DARK_PURPLE('5'),
|
||||
/**
|
||||
* Represents gold
|
||||
* Represents gold.
|
||||
*/
|
||||
GOLD('6', 0x6),
|
||||
GOLD('6'),
|
||||
/**
|
||||
* Represents gray
|
||||
* Represents gray.
|
||||
*/
|
||||
GRAY('7', 0x7),
|
||||
GRAY('7'),
|
||||
/**
|
||||
* Represents dark gray
|
||||
* Represents dark gray.
|
||||
*/
|
||||
DARK_GRAY('8', 0x8),
|
||||
DARK_GRAY('8'),
|
||||
/**
|
||||
* Represents blue
|
||||
* Represents blue.
|
||||
*/
|
||||
BLUE('9', 0x9),
|
||||
BLUE('9'),
|
||||
/**
|
||||
* Represents green
|
||||
* Represents green.
|
||||
*/
|
||||
GREEN('a', 0xA),
|
||||
GREEN('a'),
|
||||
/**
|
||||
* Represents aqua
|
||||
* Represents aqua.
|
||||
*/
|
||||
AQUA('b', 0xB),
|
||||
AQUA('b'),
|
||||
/**
|
||||
* Represents red
|
||||
* Represents red.
|
||||
*/
|
||||
RED('c', 0xC),
|
||||
RED('c'),
|
||||
/**
|
||||
* Represents light purple
|
||||
* Represents light purple.
|
||||
*/
|
||||
LIGHT_PURPLE('d', 0xD),
|
||||
LIGHT_PURPLE('d'),
|
||||
/**
|
||||
* Represents yellow
|
||||
* Represents yellow.
|
||||
*/
|
||||
YELLOW('e', 0xE),
|
||||
YELLOW('e'),
|
||||
/**
|
||||
* Represents white
|
||||
* Represents white.
|
||||
*/
|
||||
WHITE('f', 0xF),
|
||||
WHITE('f'),
|
||||
/**
|
||||
* Represents magical characters that change around randomly
|
||||
* Represents magical characters that change around randomly.
|
||||
*/
|
||||
MAGIC('k', 0x10, true),
|
||||
MAGIC('k'),
|
||||
/**
|
||||
* Makes the text bold.
|
||||
*/
|
||||
BOLD('l', 0x11, true),
|
||||
BOLD('l'),
|
||||
/**
|
||||
* Makes a line appear through the text.
|
||||
*/
|
||||
STRIKETHROUGH('m', 0x12, true),
|
||||
STRIKETHROUGH('m'),
|
||||
/**
|
||||
* Makes the text appear underlined.
|
||||
*/
|
||||
UNDERLINE('n', 0x13, true),
|
||||
UNDERLINE('n'),
|
||||
/**
|
||||
* Makes the text italic.
|
||||
*/
|
||||
ITALIC('o', 0x14, true),
|
||||
ITALIC('o'),
|
||||
/**
|
||||
* Resets all previous chat colors or formats.
|
||||
*/
|
||||
RESET('r', 0x15);
|
||||
RESET('r');
|
||||
/**
|
||||
* The special character which prefixes all chat colour codes. Use this if
|
||||
* you need to dynamically convert colour codes from your custom format.
|
||||
*/
|
||||
public static final char COLOR_CHAR = '\u00A7';
|
||||
private static final Pattern STRIP_COLOR_PATTERN = Pattern.compile("(?i)" + String.valueOf(COLOR_CHAR) + "[0-9A-FK-OR]");
|
||||
private final int intCode;
|
||||
private final char code;
|
||||
private final boolean isFormat;
|
||||
private final String toString;
|
||||
private final static Map<Integer, ChatColor> BY_ID = Maps.newHashMap();
|
||||
private final static Map<Character, ChatColor> BY_CHAR = Maps.newHashMap();
|
||||
|
||||
private ChatColor(char code, int intCode) {
|
||||
this(code, intCode, false);
|
||||
}
|
||||
|
||||
private ChatColor(char code, int intCode, boolean isFormat) {
|
||||
this.code = code;
|
||||
this.intCode = intCode;
|
||||
this.isFormat = isFormat;
|
||||
this.toString = new String(new char[]{COLOR_CHAR, code});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the char value associated with this color
|
||||
*
|
||||
* @return A char value of this color code
|
||||
* Pattern to remove all colour codes.
|
||||
*/
|
||||
public char getChar() {
|
||||
return code;
|
||||
private static final Pattern STRIP_COLOR_PATTERN = Pattern.compile("(?i)" + String.valueOf(COLOR_CHAR) + "[0-9A-FK-OR]");
|
||||
/**
|
||||
* This colour's colour char prefixed by the {@link #COLOR_CHAR}.
|
||||
*/
|
||||
private final String toString;
|
||||
|
||||
private ChatColor(char code) {
|
||||
this.toString = new String(new char[]{COLOR_CHAR, code});
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -135,31 +118,6 @@ public enum ChatColor {
|
||||
return toString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this code is a format code as opposed to a color code.
|
||||
*/
|
||||
public boolean isFormat() {
|
||||
return isFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this code is a color code as opposed to a format code.
|
||||
*/
|
||||
public boolean isColor() {
|
||||
return !isFormat && this != RESET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the color represented by the specified color code
|
||||
*
|
||||
* @param code Code to check
|
||||
* @return Associative {@link org.bukkit.ChatColor} with the given code, or
|
||||
* null if it doesn't exist
|
||||
*/
|
||||
public static ChatColor getByChar(char code) {
|
||||
return BY_CHAR.get(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips the given message of all color codes
|
||||
*
|
||||
@ -173,64 +131,4 @@ public enum ChatColor {
|
||||
|
||||
return STRIP_COLOR_PATTERN.matcher(input).replaceAll("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a string using an alternate color code character into a string
|
||||
* that uses the internal ChatColor.COLOR_CODE color code character. The
|
||||
* alternate color code character will only be replaced if it is immediately
|
||||
* followed by 0-9, A-F, or a-f.
|
||||
*
|
||||
* @param altColorChar The alternate color code character to replace. Ex: &
|
||||
* @param textToTranslate Text containing the alternate color code
|
||||
* character.
|
||||
* @return Text containing the ChatColor.COLOR_CODE color code character.
|
||||
*/
|
||||
public static String translateAlternateColorCodes(char altColorChar, String textToTranslate) {
|
||||
char[] b = textToTranslate.toCharArray();
|
||||
for (int i = 0; i < b.length - 1; i++) {
|
||||
if (b[i] == altColorChar && "0123456789AaBbCcDdEeFfKkLlMmNnOoRr".indexOf(b[i + 1]) > -1) {
|
||||
b[i] = ChatColor.COLOR_CHAR;
|
||||
b[i + 1] = Character.toLowerCase(b[i + 1]);
|
||||
}
|
||||
}
|
||||
return new String(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ChatColors used at the end of the given input string.
|
||||
*
|
||||
* @param input Input string to retrieve the colors from.
|
||||
* @return Any remaining ChatColors to pass onto the next line.
|
||||
*/
|
||||
public static String getLastColors(String input) {
|
||||
String result = "";
|
||||
int length = input.length();
|
||||
|
||||
// Search backwards from the end as it is faster
|
||||
for (int index = length - 1; index > -1; index--) {
|
||||
char section = input.charAt(index);
|
||||
if (section == COLOR_CHAR && index < length - 1) {
|
||||
char c = input.charAt(index + 1);
|
||||
ChatColor color = getByChar(c);
|
||||
|
||||
if (color != null) {
|
||||
result = color.toString() + result;
|
||||
|
||||
// Once we find a color or reset we can stop searching
|
||||
if (color.isColor() || color.equals(RESET)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static {
|
||||
for (ChatColor color : values()) {
|
||||
BY_ID.put(color.intCode, color);
|
||||
BY_CHAR.put(color.code, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,9 @@ import static net.md_5.bungee.Logger.$;
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
/**
|
||||
* Core configuration for the proxy.
|
||||
*/
|
||||
public class Configuration {
|
||||
|
||||
/**
|
||||
@ -97,6 +100,9 @@ public class Configuration {
|
||||
*/
|
||||
public int logNumLines = 1 << 14;
|
||||
|
||||
/**
|
||||
* Load the configuration and save default values.
|
||||
*/
|
||||
public void load() {
|
||||
try {
|
||||
file.createNewFile();
|
||||
@ -172,11 +178,17 @@ public class Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
public String getServerFor(String user, String requestedHost) {
|
||||
String server;
|
||||
if (forcedServers.containsKey(requestedHost)) {
|
||||
server = servers.get(forcedServers.get(requestedHost));
|
||||
} else {
|
||||
/**
|
||||
* Get which server a user should be connected to, taking into account their
|
||||
* name and virtual host.
|
||||
*
|
||||
* @param user to get a server for
|
||||
* @param requestedHost the host which they connected to
|
||||
* @return the name of the server which they should be connected to.
|
||||
*/
|
||||
public String getServer(String user, String requestedHost) {
|
||||
String server = forcedServers.get(requestedHost);
|
||||
if (server == null) {
|
||||
server = reconnectLocations.get(user);
|
||||
}
|
||||
if (server == null) {
|
||||
@ -185,20 +197,30 @@ public class Configuration {
|
||||
return server;
|
||||
}
|
||||
|
||||
public void setHostFor(UserConnection user, String server) {
|
||||
/**
|
||||
* Save the last server which the user was on.
|
||||
*
|
||||
* @param user the name of the user
|
||||
* @param server which they were last on
|
||||
*/
|
||||
public void setServer(UserConnection user, String server) {
|
||||
reconnectLocations.put(user.username, server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the connectable address of a server defined in the configuration.
|
||||
*
|
||||
* @param name the friendly name of a server
|
||||
* @return the usable {@link InetSocketAddress} mapped to this server
|
||||
*/
|
||||
public InetSocketAddress getServer(String name) {
|
||||
String hostline = (name == null) ? defaultServerName : name;
|
||||
String server = servers.get(hostline);
|
||||
if (server != null) {
|
||||
return Util.getAddr(server);
|
||||
} else {
|
||||
return getServer(null);
|
||||
}
|
||||
String server = servers.get((name == null) ? defaultServerName : name);
|
||||
return (server != null) ? Util.getAddr(server) : getServer(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the current mappings of users to servers.
|
||||
*/
|
||||
public void saveHosts() {
|
||||
save(reconnect, reconnectLocations);
|
||||
$().info("Saved reconnect locations to " + reconnect);
|
||||
|
@ -35,6 +35,9 @@ import org.bouncycastle.crypto.params.KeyParameter;
|
||||
import org.bouncycastle.crypto.params.ParametersWithIV;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
|
||||
/**
|
||||
* Class containing all encryption related methods for the proxy.
|
||||
*/
|
||||
public class EncryptionUtil {
|
||||
|
||||
private static final Random secure = new SecureRandom();
|
||||
@ -57,9 +60,7 @@ public class EncryptionUtil {
|
||||
return new PacketFDEncryptionRequest(hash, pubKey, verify);
|
||||
}
|
||||
|
||||
public static SecretKey getSecret(PacketFCEncryptionResponse resp, PacketFDEncryptionRequest request) throws BadPaddingException, IllegalBlockSizeException,
|
||||
IllegalStateException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
|
||||
|
||||
public static SecretKey getSecret(PacketFCEncryptionResponse resp, PacketFDEncryptionRequest request) throws BadPaddingException, IllegalBlockSizeException, IllegalStateException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
|
||||
Cipher cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.DECRYPT_MODE, keys.getPrivate());
|
||||
byte[] decrypted = cipher.doFinal(resp.verifyToken);
|
||||
|
@ -1,5 +1,8 @@
|
||||
package net.md_5.bungee;
|
||||
|
||||
/**
|
||||
* Class to rewrite integers within packets.
|
||||
*/
|
||||
public class EntityMap {
|
||||
|
||||
public final static int[][] entityIds = new int[256][];
|
||||
|
@ -9,6 +9,9 @@ import static net.md_5.bungee.Logger.$;
|
||||
import net.md_5.bungee.packet.PacketFFKick;
|
||||
import net.md_5.bungee.packet.PacketInputStream;
|
||||
|
||||
/**
|
||||
* Class to represent a Minecraft connection.
|
||||
*/
|
||||
@EqualsAndHashCode
|
||||
@RequiredArgsConstructor
|
||||
public class GenericConnection {
|
||||
@ -18,6 +21,11 @@ public class GenericConnection {
|
||||
protected final OutputStream out;
|
||||
public String username;
|
||||
|
||||
/**
|
||||
* Close the socket with the specified reason.
|
||||
*
|
||||
* @param reason to disconnect
|
||||
*/
|
||||
public void disconnect(String reason) {
|
||||
if (socket.isClosed()) {
|
||||
return;
|
||||
|
@ -9,7 +9,7 @@ import net.md_5.bungee.packet.PacketFCEncryptionResponse;
|
||||
import net.md_5.bungee.packet.PacketFDEncryptionRequest;
|
||||
import net.md_5.bungee.packet.PacketFFKick;
|
||||
import net.md_5.bungee.packet.PacketInputStream;
|
||||
import net.md_5.bungee.plugin.ConnectEvent;
|
||||
import net.md_5.bungee.plugin.HandshakeEvent;
|
||||
import org.bouncycastle.crypto.io.CipherInputStream;
|
||||
import org.bouncycastle.crypto.io.CipherOutputStream;
|
||||
|
||||
@ -34,8 +34,8 @@ public class InitialHandler implements Runnable {
|
||||
case 0x02:
|
||||
Packet2Handshake handshake = new Packet2Handshake(packet);
|
||||
// fire connect event
|
||||
ConnectEvent event = new ConnectEvent(handshake.username, socket.getInetAddress());
|
||||
BungeeCord.instance.pluginManager.onConnect(event);
|
||||
HandshakeEvent event = new HandshakeEvent(handshake.username, socket.getInetAddress());
|
||||
BungeeCord.instance.pluginManager.onHandshake(event);
|
||||
if (event.isCancelled()) {
|
||||
throw new KickException(event.getCancelReason());
|
||||
}
|
||||
@ -59,8 +59,7 @@ public class InitialHandler implements Runnable {
|
||||
}
|
||||
|
||||
UserConnection userCon = new UserConnection(socket, in, out, handshake);
|
||||
userCon.register();
|
||||
userCon.connect(BungeeCord.instance.config.getServerFor(handshake.username, handshake.host));
|
||||
userCon.connect(BungeeCord.instance.config.getServer(handshake.username, handshake.host));
|
||||
break;
|
||||
case 0xFE:
|
||||
throw new KickException(BungeeCord.instance.config.motd + ChatColor.COLOR_CHAR + BungeeCord.instance.connections.size() + ChatColor.COLOR_CHAR + BungeeCord.instance.config.maxPlayers);
|
||||
|
@ -1,5 +1,9 @@
|
||||
package net.md_5.bungee;
|
||||
|
||||
/**
|
||||
* Exception, which when thrown will disconnect the player from the proxy with
|
||||
* the specified message.
|
||||
*/
|
||||
public class KickException extends RuntimeException {
|
||||
|
||||
public KickException(String message) {
|
||||
|
@ -7,6 +7,9 @@ import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import static net.md_5.bungee.Logger.$;
|
||||
|
||||
/**
|
||||
* Thread to listen and dispatch incoming connections to the proxy.
|
||||
*/
|
||||
public class ListenThread extends Thread {
|
||||
|
||||
public final ServerSocket socket;
|
||||
|
@ -9,6 +9,9 @@ import java.util.logging.Formatter;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
|
||||
/**
|
||||
* Logger to handle formatting and storage of the proxy's logger.
|
||||
*/
|
||||
public class Logger extends java.util.logging.Logger {
|
||||
|
||||
private static final Formatter formatter = new ConsoleLogFormatter();
|
||||
@ -20,7 +23,7 @@ public class Logger extends java.util.logging.Logger {
|
||||
FileHandler handler = new FileHandler("proxy.log", BungeeCord.instance.config.logNumLines, 1, true);
|
||||
handler.setFormatter(formatter);
|
||||
addHandler(handler);
|
||||
} catch (IOException | SecurityException ex) {
|
||||
} catch (IOException ex) {
|
||||
System.err.println("Could not register logger!");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
@ -37,6 +40,11 @@ public class Logger extends java.util.logging.Logger {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current logger instance.
|
||||
*
|
||||
* @return the current logger instance
|
||||
*/
|
||||
public static Logger $() {
|
||||
return instance;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
package net.md_5.bungee;
|
||||
|
||||
/**
|
||||
* Class to call the {@link Configuration#saveHosts() } method at 5 minute
|
||||
* intervals.
|
||||
*/
|
||||
public class ReconnectSaveThread extends Thread {
|
||||
|
||||
public ReconnectSaveThread() {
|
||||
|
@ -16,6 +16,9 @@ import net.md_5.bungee.packet.PacketInputStream;
|
||||
import org.bouncycastle.crypto.io.CipherInputStream;
|
||||
import org.bouncycastle.crypto.io.CipherOutputStream;
|
||||
|
||||
/**
|
||||
* Class representing a connection from the proxy to the server; ie upstream.
|
||||
*/
|
||||
public class ServerConnection extends GenericConnection {
|
||||
|
||||
public final String name;
|
||||
|
@ -33,14 +33,11 @@ public class UserConnection extends GenericConnection implements CommandSender {
|
||||
super(socket, in, out);
|
||||
this.handshake = handshake;
|
||||
username = handshake.username;
|
||||
BungeeCord.instance.connections.put(username, this);
|
||||
}
|
||||
|
||||
public void connect(String server) {
|
||||
InetSocketAddress addr = BungeeCord.instance.config.getServer(server);
|
||||
if (addr.equals(curServer())) {
|
||||
sendMessage(ChatColor.RED + "You are already on this server");
|
||||
return;
|
||||
}
|
||||
connect(server, addr);
|
||||
}
|
||||
|
||||
@ -83,14 +80,6 @@ public class UserConnection extends GenericConnection implements CommandSender {
|
||||
}
|
||||
}
|
||||
|
||||
public void register() {
|
||||
BungeeCord.instance.connections.put(username, this);
|
||||
}
|
||||
|
||||
private InetSocketAddress curServer() {
|
||||
return (server == null) ? null : new InetSocketAddress(server.socket.getInetAddress(), server.socket.getPort());
|
||||
}
|
||||
|
||||
private void destory(String reason) {
|
||||
if (BungeeCord.instance.isRunning) {
|
||||
BungeeCord.instance.connections.remove(username);
|
||||
@ -98,9 +87,7 @@ public class UserConnection extends GenericConnection implements CommandSender {
|
||||
disconnect(reason);
|
||||
if (server != null) {
|
||||
server.disconnect("Quitting");
|
||||
}
|
||||
if (server != null) {
|
||||
BungeeCord.instance.config.setHostFor(this, server.name);
|
||||
BungeeCord.instance.config.setServer(this, server.name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,13 +2,15 @@ package net.md_5.bungee;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* Series of utility classes to perform various operations.
|
||||
*/
|
||||
public class Util {
|
||||
|
||||
private static final int DEFAULT_PORT = 25565;
|
||||
|
||||
/**
|
||||
* Basic method to transform human readable addresses into usable address
|
||||
* objects.
|
||||
* Method to transform human readable addresses into usable address objects.
|
||||
*
|
||||
* @param hostline in the format of 'host:port'
|
||||
* @return the constructed hostname + port.
|
||||
@ -23,17 +25,11 @@ public class Util {
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns a InetSocketAddress into a string that can be reconstructed later.
|
||||
* Gets the value of the first unsigned byte of the specified array. Useful
|
||||
* for getting the id of a packet array .
|
||||
*
|
||||
* @param address the address to serialize
|
||||
* @return
|
||||
*/
|
||||
public static String getAddr(InetSocketAddress address) {
|
||||
return address.getAddress().getHostAddress() + ((address.getPort() != DEFAULT_PORT) ? ":" + address.getPort() : "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the packet id of specified byte array.
|
||||
* @param b the array to read from
|
||||
* @return the unsigned value of the first byte
|
||||
*/
|
||||
public static int getId(byte[] b) {
|
||||
return b[0] & 0xFF;
|
||||
@ -57,10 +53,23 @@ public class Util {
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an integer as a hex value.
|
||||
*
|
||||
* @param i the integer to format
|
||||
* @return the hex representation of the integer
|
||||
*/
|
||||
public static String hex(int i) {
|
||||
return String.format("0x%02X", i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a pretty one line version of a {@link Throwable}. Useful for
|
||||
* debugging.
|
||||
*
|
||||
* @param t the {@link Throwable} to format.
|
||||
* @return a string representing information about the {@link Throwable}
|
||||
*/
|
||||
public static String exception(Throwable t) {
|
||||
return t.getClass().getSimpleName() + " : " + t.getMessage() + " @ " + t.getStackTrace()[0].getFileName() + ":" + t.getStackTrace()[0].getLineNumber();
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
package net.md_5.bungee.command;
|
||||
|
||||
import net.md_5.bungee.ChatColor;
|
||||
|
||||
/**
|
||||
* Class which represents a proxy command. The {@link #execute(net.md_5.bungee.command.CommandSender, java.lang.String[])
|
||||
* } method will be called to dispatch the command.
|
||||
*/
|
||||
public abstract class Command {
|
||||
|
||||
/**
|
||||
@ -12,20 +14,4 @@ public abstract class Command {
|
||||
* the original command.
|
||||
*/
|
||||
public abstract void execute(CommandSender sender, String[] args);
|
||||
|
||||
/**
|
||||
* Check if the arg count is at least the specified amount
|
||||
*
|
||||
* @param sender sender to send message to if unsuccessful
|
||||
* @param args to check
|
||||
* @param count to compare
|
||||
* @return if the arguments are valid
|
||||
*/
|
||||
public final boolean testArgs(CommandSender sender, String[] args, int count) {
|
||||
boolean valid = args.length >= count;
|
||||
if (!valid) {
|
||||
sender.sendMessage(ChatColor.RED + "Please review your argument count");
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,9 @@ package net.md_5.bungee.command;
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.ChatColor;
|
||||
|
||||
/**
|
||||
* Command to terminate the proxy instance. May only be used by the console.
|
||||
*/
|
||||
public class CommandEnd extends Command {
|
||||
|
||||
@Override
|
||||
|
@ -5,6 +5,9 @@ import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.ChatColor;
|
||||
import net.md_5.bungee.UserConnection;
|
||||
|
||||
/**
|
||||
* Command to list all players connected to the proxy.
|
||||
*/
|
||||
public class CommandList extends Command {
|
||||
|
||||
@Override
|
||||
@ -14,7 +17,6 @@ public class CommandList extends Command {
|
||||
|
||||
for (UserConnection con : connections) {
|
||||
users.append(con.username);
|
||||
users.append(ChatColor.RESET.toString());
|
||||
users.append(", ");
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,9 @@ import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.ChatColor;
|
||||
import net.md_5.bungee.UserConnection;
|
||||
|
||||
/**
|
||||
* Command to list and switch a player between availible servers.
|
||||
*/
|
||||
public class CommandServer extends Command {
|
||||
|
||||
@Override
|
||||
|
@ -2,6 +2,9 @@ package net.md_5.bungee.command;
|
||||
|
||||
import net.md_5.bungee.ChatColor;
|
||||
|
||||
/**
|
||||
* Command sender representing the proxy console.
|
||||
*/
|
||||
public class ConsoleCommandSender implements CommandSender {
|
||||
|
||||
public static final ConsoleCommandSender instance = new ConsoleCommandSender();
|
||||
|
@ -8,6 +8,11 @@ import java.io.DataOutput;
|
||||
import lombok.Delegate;
|
||||
import net.md_5.bungee.Util;
|
||||
|
||||
/**
|
||||
* This class represents a packet which has been given a special definition. All
|
||||
* subclasses can read and write to the backing byte array which can be
|
||||
* retrieved via the {@link #getPacket()} method.
|
||||
*/
|
||||
public abstract class DefinedPacket implements DataInput, DataOutput {
|
||||
|
||||
private interface Overriden {
|
||||
@ -44,6 +49,12 @@ public abstract class DefinedPacket implements DataInput, DataOutput {
|
||||
writeByte(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the bytes that make up this packet.
|
||||
*
|
||||
* @return the bytes which make up this packet, either the original byte
|
||||
* array or the newly written one.
|
||||
*/
|
||||
public byte[] getPacket() {
|
||||
return packet == null ? out.toByteArray() : packet;
|
||||
}
|
||||
|
@ -8,6 +8,10 @@ import java.io.InputStream;
|
||||
import net.md_5.bungee.Util;
|
||||
import net.minecraft.server.Packet;
|
||||
|
||||
/**
|
||||
* A specialized input stream to parse packets using the Mojang packet
|
||||
* definitions and then return them as a byte array.
|
||||
*/
|
||||
public class PacketInputStream {
|
||||
|
||||
private final DataInputStream dataInput;
|
||||
@ -18,6 +22,12 @@ public class PacketInputStream {
|
||||
dataInput = new DataInputStream(tracker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an entire packet from the stream and return it as a byte array.
|
||||
*
|
||||
* @return the read packet
|
||||
* @throws IOException when the underlying input stream throws an exception
|
||||
*/
|
||||
public byte[] readPacket() throws IOException {
|
||||
tracker.out.reset();
|
||||
int id = tracker.read();
|
||||
@ -33,6 +43,10 @@ public class PacketInputStream {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Input stream which will wrap another stream and copy all bytes read to a
|
||||
* {@link ByteArrayOutputStream}.
|
||||
*/
|
||||
private class TrackingInputStream extends InputStream {
|
||||
|
||||
private final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
@ -80,13 +80,25 @@ import net.minecraft.server.Packet7UseEntity;
|
||||
import net.minecraft.server.Packet8UpdateHealth;
|
||||
import net.minecraft.server.Packet9Respawn;
|
||||
|
||||
/**
|
||||
* Class containing instances of all Vanilla Minecraft packets.
|
||||
*/
|
||||
public class VanillaPackets {
|
||||
|
||||
/**
|
||||
* Array of packet instances ordered by packet id.
|
||||
*/
|
||||
public static Packet[] packets = new Packet[256];
|
||||
|
||||
private static void map(int id, Class clazz) {
|
||||
/**
|
||||
* Adds a new instance of a packet class to the array storage.
|
||||
*
|
||||
* @param id of the packet to add
|
||||
* @param clazz class of the packet to add
|
||||
*/
|
||||
private static void map(int id, Class<? extends Packet> clazz) {
|
||||
try {
|
||||
packets[id] = (Packet) clazz.getDeclaredConstructor().newInstance();
|
||||
packets[id] = clazz.getDeclaredConstructor().newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException ex) {
|
||||
$().severe("Could not register packet id " + Util.hex(id));
|
||||
}
|
||||
|
@ -1,8 +1,21 @@
|
||||
package net.md_5.bungee.plugin;
|
||||
|
||||
/**
|
||||
* An event which may be canceled and this be prevented from happening.
|
||||
*/
|
||||
public interface Cancellable {
|
||||
|
||||
public void setCancelled(boolean cancelled);
|
||||
/**
|
||||
* Sets the canceled state of this event.
|
||||
*
|
||||
* @param canceled whether this event is canceled or not
|
||||
*/
|
||||
public void setCancelled(boolean canceled);
|
||||
|
||||
/**
|
||||
* Gets the canceled state of this event.
|
||||
*
|
||||
* @return whether this event is canceled or not
|
||||
*/
|
||||
public boolean isCancelled();
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
package net.md_5.bungee.plugin;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ConnectEvent implements Cancellable {
|
||||
|
||||
private boolean cancelled;
|
||||
private String cancelReason;
|
||||
private final String username;
|
||||
private final InetAddress address;
|
||||
}
|
30
src/main/java/net/md_5/bungee/plugin/HandshakeEvent.java
Normal file
30
src/main/java/net/md_5/bungee/plugin/HandshakeEvent.java
Normal file
@ -0,0 +1,30 @@
|
||||
package net.md_5.bungee.plugin;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Event called once a remote connection has begun the login procedure. This
|
||||
* event is ideal for IP banning, however must be used with care in other places
|
||||
* such as logging at the username has not yet been verified with Mojang.
|
||||
*/
|
||||
@Data
|
||||
public class HandshakeEvent implements Cancellable {
|
||||
|
||||
/**
|
||||
* Canceled state.
|
||||
*/
|
||||
private boolean cancelled;
|
||||
/**
|
||||
* Message to use when kicking if this event is canceled.
|
||||
*/
|
||||
private String cancelReason;
|
||||
/**
|
||||
* Username which the player wishes to use.
|
||||
*/
|
||||
private final String username;
|
||||
/**
|
||||
* IP address of the remote connection.
|
||||
*/
|
||||
private final InetAddress address;
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
package net.md_5.bungee.plugin;
|
||||
|
||||
/**
|
||||
* Exception thrown when a plugin could not be loaded for any reason.
|
||||
*/
|
||||
public class InvalidPluginException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
@ -3,6 +3,9 @@ package net.md_5.bungee.plugin;
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.command.Command;
|
||||
|
||||
/**
|
||||
* Base class which all proxy plugins should extend.
|
||||
*/
|
||||
public abstract class JavaPlugin {
|
||||
|
||||
/**
|
||||
@ -26,13 +29,13 @@ public abstract class JavaPlugin {
|
||||
* Called when a user connects with their name and address. To keep things
|
||||
* simple this name has not been checked with minecraft.net.
|
||||
*/
|
||||
public void onConnect(ConnectEvent event) {
|
||||
public void onHandshake(HandshakeEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a command.
|
||||
* Register a command for use with the proxy.
|
||||
*/
|
||||
protected void registerCommand(String label, Command command) {
|
||||
protected final void registerCommand(String label, Command command) {
|
||||
BungeeCord.instance.commandMap.put(label, command);
|
||||
}
|
||||
}
|
||||
|
@ -12,11 +12,22 @@ import java.util.zip.ZipEntry;
|
||||
import lombok.Getter;
|
||||
import static net.md_5.bungee.Logger.$;
|
||||
|
||||
/**
|
||||
* Plugin manager to handle loading and saving other JavaPlugin's. This class is
|
||||
* itself a plugin for ease of use.
|
||||
*/
|
||||
public class JavaPluginManager extends JavaPlugin {
|
||||
|
||||
/**
|
||||
* Set of loaded plugins.
|
||||
*/
|
||||
@Getter
|
||||
private final Set<JavaPlugin> plugins = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Load all plugins from the plugins folder. This method must only be called
|
||||
* once per instance.
|
||||
*/
|
||||
public void loadPlugins() {
|
||||
File dir = new File("plugins");
|
||||
dir.mkdir();
|
||||
@ -58,9 +69,9 @@ public class JavaPluginManager extends JavaPlugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnect(ConnectEvent event) {
|
||||
public void onHandshake(HandshakeEvent event) {
|
||||
for (JavaPlugin p : plugins) {
|
||||
p.onConnect(event);
|
||||
p.onHandshake(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,10 @@ import java.lang.reflect.Field;
|
||||
import lombok.Data;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
/**
|
||||
* File which contains information about a plugin, its authors, and how to load
|
||||
* it.
|
||||
*/
|
||||
@Data
|
||||
public class PluginDescription {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user