A ton of javadocs and small fixes in preparation for rewriting bridge system and eventual release.

This commit is contained in:
md_5 2012-10-12 22:20:37 +11:00
parent c6749726c5
commit aa2710c573
29 changed files with 316 additions and 249 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -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][];

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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