Nothing like a change of coding style to neaten things up.
This commit is contained in:
parent
e0b738e188
commit
6c66e18262
@ -26,7 +26,8 @@ import net.md_5.bungee.plugin.JavaPluginManager;
|
|||||||
/**
|
/**
|
||||||
* Main BungeeCord proxy class.
|
* Main BungeeCord proxy class.
|
||||||
*/
|
*/
|
||||||
public class BungeeCord {
|
public class BungeeCord
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current software instance.
|
* Current software instance.
|
||||||
@ -69,6 +70,7 @@ public class BungeeCord {
|
|||||||
*/
|
*/
|
||||||
public final JavaPluginManager pluginManager = new JavaPluginManager();
|
public final JavaPluginManager pluginManager = new JavaPluginManager();
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
commandMap.put("end", new CommandEnd());
|
commandMap.put("end", new CommandEnd());
|
||||||
commandMap.put("glist", new CommandList());
|
commandMap.put("glist", new CommandList());
|
||||||
@ -83,17 +85,21 @@ public class BungeeCord {
|
|||||||
* @param args command line arguments, currently none are used
|
* @param args command line arguments, currently none are used
|
||||||
* @throws IOException when the server cannot be started
|
* @throws IOException when the server cannot be started
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException
|
||||||
|
{
|
||||||
instance = new BungeeCord();
|
instance = new BungeeCord();
|
||||||
$().info("Enabled BungeeCord version " + instance.version);
|
$().info("Enabled BungeeCord version " + instance.version);
|
||||||
instance.start();
|
instance.start();
|
||||||
|
|
||||||
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
|
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
|
||||||
while (instance.isRunning) {
|
while (instance.isRunning)
|
||||||
|
{
|
||||||
String line = br.readLine();
|
String line = br.readLine();
|
||||||
if (line != null) {
|
if (line != null)
|
||||||
|
{
|
||||||
boolean handled = instance.dispatchCommand(line, ConsoleCommandSender.instance);
|
boolean handled = instance.dispatchCommand(line, ConsoleCommandSender.instance);
|
||||||
if (!handled) {
|
if (!handled)
|
||||||
|
{
|
||||||
System.err.println("Command not found");
|
System.err.println("Command not found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,15 +113,19 @@ public class BungeeCord {
|
|||||||
* @param sender which executed the command
|
* @param sender which executed the command
|
||||||
* @return whether the command was handled or not.
|
* @return whether the command was handled or not.
|
||||||
*/
|
*/
|
||||||
public boolean dispatchCommand(String commandLine, CommandSender sender) {
|
public boolean dispatchCommand(String commandLine, CommandSender sender)
|
||||||
|
{
|
||||||
String[] split = commandLine.trim().split(" ");
|
String[] split = commandLine.trim().split(" ");
|
||||||
String commandName = split[0].toLowerCase();
|
String commandName = split[0].toLowerCase();
|
||||||
Command command = commandMap.get(commandName);
|
Command command = commandMap.get(commandName);
|
||||||
if (command != null && !config.disabledCommands.contains(commandName)) {
|
if (command != null && !config.disabledCommands.contains(commandName))
|
||||||
|
{
|
||||||
String[] args = Arrays.copyOfRange(split, 1, split.length);
|
String[] args = Arrays.copyOfRange(split, 1, split.length);
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
command.execute(sender, args);
|
command.execute(sender, args);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
sender.sendMessage(ChatColor.RED + "An error occurred while executing this command!");
|
sender.sendMessage(ChatColor.RED + "An error occurred while executing this command!");
|
||||||
$().severe("----------------------- [Start of command error] -----------------------");
|
$().severe("----------------------- [Start of command error] -----------------------");
|
||||||
$().log(Level.SEVERE, "", ex);
|
$().log(Level.SEVERE, "", ex);
|
||||||
@ -132,7 +142,8 @@ public class BungeeCord {
|
|||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public void start() throws IOException {
|
public void start() throws IOException
|
||||||
|
{
|
||||||
config.load();
|
config.load();
|
||||||
isRunning = true;
|
isRunning = true;
|
||||||
|
|
||||||
@ -152,16 +163,19 @@ public class BungeeCord {
|
|||||||
* Destroy this proxy instance cleanly by kicking all users, saving the
|
* Destroy this proxy instance cleanly by kicking all users, saving the
|
||||||
* configuration and closing all sockets.
|
* configuration and closing all sockets.
|
||||||
*/
|
*/
|
||||||
public void stop() {
|
public void stop()
|
||||||
|
{
|
||||||
this.isRunning = false;
|
this.isRunning = false;
|
||||||
$().info("Disabling plugin");
|
$().info("Disabling plugin");
|
||||||
pluginManager.onDisable();
|
pluginManager.onDisable();
|
||||||
|
|
||||||
$().info("Closing listen thread");
|
$().info("Closing listen thread");
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
listener.socket.close();
|
listener.socket.close();
|
||||||
listener.join();
|
listener.join();
|
||||||
} catch (InterruptedException | IOException ex) {
|
} catch (InterruptedException | IOException ex)
|
||||||
|
{
|
||||||
$().severe("Could not close listen thread");
|
$().severe("Could not close listen thread");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,15 +183,18 @@ public class BungeeCord {
|
|||||||
threadPool.shutdown();
|
threadPool.shutdown();
|
||||||
|
|
||||||
$().info("Disconnecting " + connections.size() + " connections");
|
$().info("Disconnecting " + connections.size() + " connections");
|
||||||
for (UserConnection user : connections.values()) {
|
for (UserConnection user : connections.values())
|
||||||
|
{
|
||||||
user.disconnect("Proxy restarting, brb.");
|
user.disconnect("Proxy restarting, brb.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$().info("Saving reconnect locations");
|
$().info("Saving reconnect locations");
|
||||||
saveThread.interrupt();
|
saveThread.interrupt();
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
saveThread.join();
|
saveThread.join();
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
$().info("Thank you and goodbye");
|
$().info("Thank you and goodbye");
|
||||||
@ -190,7 +207,8 @@ public class BungeeCord {
|
|||||||
* @param socket to set the options on
|
* @param socket to set the options on
|
||||||
* @throws IOException when the underlying set methods thrown an exception
|
* @throws IOException when the underlying set methods thrown an exception
|
||||||
*/
|
*/
|
||||||
public void setSocketOptions(Socket socket) throws IOException {
|
public void setSocketOptions(Socket socket) throws IOException
|
||||||
|
{
|
||||||
socket.setSoTimeout(config.timeout);
|
socket.setSoTimeout(config.timeout);
|
||||||
socket.setTrafficClass(0x18);
|
socket.setTrafficClass(0x18);
|
||||||
socket.setTcpNoDelay(true);
|
socket.setTcpNoDelay(true);
|
||||||
|
@ -5,7 +5,8 @@ import java.util.regex.Pattern;
|
|||||||
/**
|
/**
|
||||||
* Simplistic enumeration of all supported color values for chat.
|
* Simplistic enumeration of all supported color values for chat.
|
||||||
*/
|
*/
|
||||||
public enum ChatColor {
|
public enum ChatColor
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents black.
|
* Represents black.
|
||||||
@ -109,12 +110,17 @@ public enum ChatColor {
|
|||||||
*/
|
*/
|
||||||
private final String toString;
|
private final String toString;
|
||||||
|
|
||||||
private ChatColor(char code) {
|
private ChatColor(char code)
|
||||||
this.toString = new String(new char[]{COLOR_CHAR, code});
|
{
|
||||||
|
this.toString = new String(new char[]
|
||||||
|
{
|
||||||
|
COLOR_CHAR, code
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString()
|
||||||
|
{
|
||||||
return toString;
|
return toString;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,8 +130,10 @@ public enum ChatColor {
|
|||||||
* @param input String to strip of color
|
* @param input String to strip of color
|
||||||
* @return A copy of the input string, without any coloring
|
* @return A copy of the input string, without any coloring
|
||||||
*/
|
*/
|
||||||
public static String stripColor(final String input) {
|
public static String stripColor(final String input)
|
||||||
if (input == null) {
|
{
|
||||||
|
if (input == null)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,8 @@ import org.yaml.snakeyaml.Yaml;
|
|||||||
/**
|
/**
|
||||||
* Core configuration for the proxy.
|
* Core configuration for the proxy.
|
||||||
*/
|
*/
|
||||||
public class Configuration {
|
public class Configuration
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reconnect locations file.
|
* Reconnect locations file.
|
||||||
@ -68,7 +69,9 @@ public class Configuration {
|
|||||||
/**
|
/**
|
||||||
* All servers.
|
* All servers.
|
||||||
*/
|
*/
|
||||||
public Map<String, String> servers = new HashMap<String, String>() {
|
public Map<String, String> servers = new HashMap<String, String>()
|
||||||
|
{
|
||||||
|
|
||||||
{
|
{
|
||||||
put(defaultServerName, "127.0.0.1:1338");
|
put(defaultServerName, "127.0.0.1:1338");
|
||||||
put("pvp", "127.0.0.1:1337");
|
put("pvp", "127.0.0.1:1337");
|
||||||
@ -77,7 +80,9 @@ public class Configuration {
|
|||||||
/**
|
/**
|
||||||
* Forced servers.
|
* Forced servers.
|
||||||
*/
|
*/
|
||||||
public Map<String, String> forcedServers = new HashMap<String, String>() {
|
public Map<String, String> forcedServers = new HashMap<String, String>()
|
||||||
|
{
|
||||||
|
|
||||||
{
|
{
|
||||||
put("pvp.md-5.net", "pvp");
|
put("pvp.md-5.net", "pvp");
|
||||||
}
|
}
|
||||||
@ -85,7 +90,9 @@ public class Configuration {
|
|||||||
/**
|
/**
|
||||||
* Proxy admins.
|
* Proxy admins.
|
||||||
*/
|
*/
|
||||||
public List<String> admins = new ArrayList<String>() {
|
public List<String> admins = new ArrayList<String>()
|
||||||
|
{
|
||||||
|
|
||||||
{
|
{
|
||||||
add("Insert Admins Here");
|
add("Insert Admins Here");
|
||||||
}
|
}
|
||||||
@ -93,7 +100,9 @@ public class Configuration {
|
|||||||
/**
|
/**
|
||||||
* Proxy moderators.
|
* Proxy moderators.
|
||||||
*/
|
*/
|
||||||
public List<String> moderators = new ArrayList<String>() {
|
public List<String> moderators = new ArrayList<String>()
|
||||||
|
{
|
||||||
|
|
||||||
{
|
{
|
||||||
add("Insert Moderators Here");
|
add("Insert Moderators Here");
|
||||||
}
|
}
|
||||||
@ -101,7 +110,9 @@ public class Configuration {
|
|||||||
/**
|
/**
|
||||||
* Commands which will be blocked completely.
|
* Commands which will be blocked completely.
|
||||||
*/
|
*/
|
||||||
public List<String> disabledCommands = new ArrayList<String>() {
|
public List<String> disabledCommands = new ArrayList<String>()
|
||||||
|
{
|
||||||
|
|
||||||
{
|
{
|
||||||
add("glist");
|
add("glist");
|
||||||
}
|
}
|
||||||
@ -118,76 +129,96 @@ public class Configuration {
|
|||||||
/**
|
/**
|
||||||
* Load the configuration and save default values.
|
* Load the configuration and save default values.
|
||||||
*/
|
*/
|
||||||
public void load() {
|
public void load()
|
||||||
try {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
file.createNewFile();
|
file.createNewFile();
|
||||||
DumperOptions options = new DumperOptions();
|
DumperOptions options = new DumperOptions();
|
||||||
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
||||||
yaml = new Yaml(options);
|
yaml = new Yaml(options);
|
||||||
|
|
||||||
try (InputStream is = new FileInputStream(file)) {
|
try (InputStream is = new FileInputStream(file))
|
||||||
|
{
|
||||||
config = (Map) yaml.load(is);
|
config = (Map) yaml.load(is);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config == null) {
|
if (config == null)
|
||||||
|
{
|
||||||
config = new LinkedHashMap<>();
|
config = new LinkedHashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
$().info("-------------- Loading configuration ----------------");
|
$().info("-------------- Loading configuration ----------------");
|
||||||
for (Field field : getClass().getDeclaredFields()) {
|
for (Field field : getClass().getDeclaredFields())
|
||||||
if (!Modifier.isTransient(field.getModifiers())) {
|
{
|
||||||
|
if (!Modifier.isTransient(field.getModifiers()))
|
||||||
|
{
|
||||||
String name = Util.normalize(field.getName());
|
String name = Util.normalize(field.getName());
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
Object def = field.get(this);
|
Object def = field.get(this);
|
||||||
Object value = get(name, def);
|
Object value = get(name, def);
|
||||||
|
|
||||||
field.set(this, value);
|
field.set(this, value);
|
||||||
|
|
||||||
$().info(name + ": " + value);
|
$().info(name + ": " + value);
|
||||||
} catch (IllegalAccessException ex) {
|
} catch (IllegalAccessException ex)
|
||||||
|
{
|
||||||
$().severe("Could not get config node: " + name);
|
$().severe("Could not get config node: " + name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$().info("-----------------------------------------------------");
|
$().info("-----------------------------------------------------");
|
||||||
|
|
||||||
if (servers.get(defaultServerName) == null) {
|
if (servers.get(defaultServerName) == null)
|
||||||
|
{
|
||||||
throw new IllegalArgumentException("Server '" + defaultServerName + "' not defined");
|
throw new IllegalArgumentException("Server '" + defaultServerName + "' not defined");
|
||||||
}
|
}
|
||||||
for (String server : forcedServers.values()) {
|
for (String server : forcedServers.values())
|
||||||
if (!servers.containsKey(server)) {
|
{
|
||||||
|
if (!servers.containsKey(server))
|
||||||
|
{
|
||||||
throw new IllegalArgumentException("Forced server " + server + " is not defined in servers");
|
throw new IllegalArgumentException("Forced server " + server + " is not defined in servers");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reconnect.createNewFile();
|
reconnect.createNewFile();
|
||||||
try (FileInputStream recon = new FileInputStream(reconnect)) {
|
try (FileInputStream recon = new FileInputStream(reconnect))
|
||||||
|
{
|
||||||
reconnectLocations = (Map) yaml.load(recon);
|
reconnectLocations = (Map) yaml.load(recon);
|
||||||
}
|
}
|
||||||
if (reconnectLocations == null) {
|
if (reconnectLocations == null)
|
||||||
|
{
|
||||||
reconnectLocations = new LinkedHashMap<>();
|
reconnectLocations = new LinkedHashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex)
|
||||||
|
{
|
||||||
$().severe("Could not load config!");
|
$().severe("Could not load config!");
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> T get(String path, T def) {
|
private <T> T get(String path, T def)
|
||||||
if (!config.containsKey(path)) {
|
{
|
||||||
|
if (!config.containsKey(path))
|
||||||
|
{
|
||||||
config.put(path, def);
|
config.put(path, def);
|
||||||
save(file, config);
|
save(file, config);
|
||||||
}
|
}
|
||||||
return (T) config.get(path);
|
return (T) config.get(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void save(File fileToSave, Map toSave) {
|
private void save(File fileToSave, Map toSave)
|
||||||
try {
|
{
|
||||||
try (FileWriter wr = new FileWriter(fileToSave)) {
|
try
|
||||||
|
{
|
||||||
|
try (FileWriter wr = new FileWriter(fileToSave))
|
||||||
|
{
|
||||||
yaml.dump(toSave, wr);
|
yaml.dump(toSave, wr);
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex)
|
||||||
|
{
|
||||||
$().severe("Could not save config file " + fileToSave);
|
$().severe("Could not save config file " + fileToSave);
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -201,12 +232,15 @@ public class Configuration {
|
|||||||
* @param requestedHost the host which they connected to
|
* @param requestedHost the host which they connected to
|
||||||
* @return the name of the server which they should be connected to.
|
* @return the name of the server which they should be connected to.
|
||||||
*/
|
*/
|
||||||
public String getServer(String user, String requestedHost) {
|
public String getServer(String user, String requestedHost)
|
||||||
|
{
|
||||||
String server = forcedServers.get(requestedHost);
|
String server = forcedServers.get(requestedHost);
|
||||||
if (server == null) {
|
if (server == null)
|
||||||
|
{
|
||||||
server = reconnectLocations.get(user);
|
server = reconnectLocations.get(user);
|
||||||
}
|
}
|
||||||
if (server == null) {
|
if (server == null)
|
||||||
|
{
|
||||||
server = servers.get(defaultServerName);
|
server = servers.get(defaultServerName);
|
||||||
}
|
}
|
||||||
return server;
|
return server;
|
||||||
@ -218,7 +252,8 @@ public class Configuration {
|
|||||||
* @param user the name of the user
|
* @param user the name of the user
|
||||||
* @param server which they were last on
|
* @param server which they were last on
|
||||||
*/
|
*/
|
||||||
public void setServer(UserConnection user, String server) {
|
public void setServer(UserConnection user, String server)
|
||||||
|
{
|
||||||
reconnectLocations.put(user.username, server);
|
reconnectLocations.put(user.username, server);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,7 +263,8 @@ public class Configuration {
|
|||||||
* @param name the friendly name of a server
|
* @param name the friendly name of a server
|
||||||
* @return the usable {@link InetSocketAddress} mapped to this server
|
* @return the usable {@link InetSocketAddress} mapped to this server
|
||||||
*/
|
*/
|
||||||
public InetSocketAddress getServer(String name) {
|
public InetSocketAddress getServer(String name)
|
||||||
|
{
|
||||||
String server = servers.get((name == null) ? defaultServerName : name);
|
String server = servers.get((name == null) ? defaultServerName : name);
|
||||||
return (server != null) ? Util.getAddr(server) : getServer(null);
|
return (server != null) ? Util.getAddr(server) : getServer(null);
|
||||||
}
|
}
|
||||||
@ -236,7 +272,8 @@ public class Configuration {
|
|||||||
/**
|
/**
|
||||||
* Save the current mappings of users to servers.
|
* Save the current mappings of users to servers.
|
||||||
*/
|
*/
|
||||||
public void saveHosts() {
|
public void saveHosts()
|
||||||
|
{
|
||||||
save(reconnect, reconnectLocations);
|
save(reconnect, reconnectLocations);
|
||||||
$().info("Saved reconnect locations to " + reconnect);
|
$().info("Saved reconnect locations to " + reconnect);
|
||||||
}
|
}
|
||||||
@ -247,11 +284,14 @@ public class Configuration {
|
|||||||
* @param sender to get permissions of
|
* @param sender to get permissions of
|
||||||
* @return their permission
|
* @return their permission
|
||||||
*/
|
*/
|
||||||
public Permission getPermission(CommandSender sender) {
|
public Permission getPermission(CommandSender sender)
|
||||||
|
{
|
||||||
Permission permission = Permission.DEFAULT;
|
Permission permission = Permission.DEFAULT;
|
||||||
if (admins.contains(sender.getName()) || sender instanceof ConsoleCommandSender) {
|
if (admins.contains(sender.getName()) || sender instanceof ConsoleCommandSender)
|
||||||
|
{
|
||||||
permission = Permission.ADMIN;
|
permission = Permission.ADMIN;
|
||||||
} else if (moderators.contains(sender.getName())) {
|
} else if (moderators.contains(sender.getName()))
|
||||||
|
{
|
||||||
permission = Permission.MODERATOR;
|
permission = Permission.MODERATOR;
|
||||||
}
|
}
|
||||||
return permission;
|
return permission;
|
||||||
|
@ -38,18 +38,22 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
|||||||
/**
|
/**
|
||||||
* Class containing all encryption related methods for the proxy.
|
* Class containing all encryption related methods for the proxy.
|
||||||
*/
|
*/
|
||||||
public class EncryptionUtil {
|
public class EncryptionUtil
|
||||||
|
{
|
||||||
|
|
||||||
private static final Random secure = new SecureRandom();
|
private static final Random secure = new SecureRandom();
|
||||||
private static final Random random = new Random();
|
private static final Random random = new Random();
|
||||||
private static KeyPair keys;
|
private static KeyPair keys;
|
||||||
|
|
||||||
static {
|
static
|
||||||
|
{
|
||||||
Security.addProvider(new BouncyCastleProvider());
|
Security.addProvider(new BouncyCastleProvider());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PacketFDEncryptionRequest encryptRequest() throws NoSuchAlgorithmException {
|
public static PacketFDEncryptionRequest encryptRequest() throws NoSuchAlgorithmException
|
||||||
if (keys == null) {
|
{
|
||||||
|
if (keys == null)
|
||||||
|
{
|
||||||
keys = KeyPairGenerator.getInstance("RSA").generateKeyPair();
|
keys = KeyPairGenerator.getInstance("RSA").generateKeyPair();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,12 +64,14 @@ public class EncryptionUtil {
|
|||||||
return new PacketFDEncryptionRequest(hash, pubKey, verify);
|
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 cipher = Cipher.getInstance("RSA");
|
||||||
cipher.init(Cipher.DECRYPT_MODE, keys.getPrivate());
|
cipher.init(Cipher.DECRYPT_MODE, keys.getPrivate());
|
||||||
byte[] decrypted = cipher.doFinal(resp.verifyToken);
|
byte[] decrypted = cipher.doFinal(resp.verifyToken);
|
||||||
|
|
||||||
if (!Arrays.equals(request.verifyToken, decrypted)) {
|
if (!Arrays.equals(request.verifyToken, decrypted))
|
||||||
|
{
|
||||||
throw new IllegalStateException("Key pairs do not match!");
|
throw new IllegalStateException("Key pairs do not match!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,47 +82,58 @@ public class EncryptionUtil {
|
|||||||
return new SecretKeySpec(secret, "AES");
|
return new SecretKeySpec(secret, "AES");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isAuthenticated(String username, String connectionHash, SecretKey shared) throws NoSuchAlgorithmException, IOException {
|
public static boolean isAuthenticated(String username, String connectionHash, SecretKey shared) throws NoSuchAlgorithmException, IOException
|
||||||
|
{
|
||||||
String encName = URLEncoder.encode(username, "UTF-8");
|
String encName = URLEncoder.encode(username, "UTF-8");
|
||||||
|
|
||||||
MessageDigest sha = MessageDigest.getInstance("SHA-1");
|
MessageDigest sha = MessageDigest.getInstance("SHA-1");
|
||||||
for (byte[] bit : new byte[][]{connectionHash.getBytes("ISO_8859_1"), shared.getEncoded(), keys.getPublic().getEncoded()}) {
|
for (byte[] bit : new byte[][]
|
||||||
|
{
|
||||||
|
connectionHash.getBytes("ISO_8859_1"), shared.getEncoded(), keys.getPublic().getEncoded()
|
||||||
|
})
|
||||||
|
{
|
||||||
sha.update(bit);
|
sha.update(bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
String encodedHash = URLEncoder.encode(new BigInteger(sha.digest()).toString(16), "UTF-8");
|
String encodedHash = URLEncoder.encode(new BigInteger(sha.digest()).toString(16), "UTF-8");
|
||||||
String authURL = "http://session.minecraft.net/game/checkserver.jsp?user=" + encName + "&serverId=" + encodedHash;
|
String authURL = "http://session.minecraft.net/game/checkserver.jsp?user=" + encName + "&serverId=" + encodedHash;
|
||||||
String reply;
|
String reply;
|
||||||
try (BufferedReader in = new BufferedReader(new InputStreamReader(new URL(authURL).openStream()))) {
|
try (BufferedReader in = new BufferedReader(new InputStreamReader(new URL(authURL).openStream())))
|
||||||
|
{
|
||||||
reply = in.readLine();
|
reply = in.readLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
return "YES".equals(reply);
|
return "YES".equals(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BufferedBlockCipher getCipher(boolean forEncryption, Key shared) {
|
public static BufferedBlockCipher getCipher(boolean forEncryption, Key shared)
|
||||||
|
{
|
||||||
BufferedBlockCipher cip = new BufferedBlockCipher(new CFBBlockCipher(new AESFastEngine(), 8));
|
BufferedBlockCipher cip = new BufferedBlockCipher(new CFBBlockCipher(new AESFastEngine(), 8));
|
||||||
cip.init(forEncryption, new ParametersWithIV(new KeyParameter(shared.getEncoded()), shared.getEncoded(), 0, 16));
|
cip.init(forEncryption, new ParametersWithIV(new KeyParameter(shared.getEncoded()), shared.getEncoded(), 0, 16));
|
||||||
return cip;
|
return cip;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SecretKey getSecret() {
|
public static SecretKey getSecret()
|
||||||
|
{
|
||||||
byte[] rand = new byte[32];
|
byte[] rand = new byte[32];
|
||||||
secure.nextBytes(rand);
|
secure.nextBytes(rand);
|
||||||
return new SecretKeySpec(rand, "AES");
|
return new SecretKeySpec(rand, "AES");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PublicKey getPubkey(PacketFDEncryptionRequest request) throws InvalidKeySpecException, NoSuchAlgorithmException {
|
public static PublicKey getPubkey(PacketFDEncryptionRequest request) throws InvalidKeySpecException, NoSuchAlgorithmException
|
||||||
|
{
|
||||||
return KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(request.publicKey));
|
return KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(request.publicKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] encrypt(Key key, byte[] b) throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
|
public static byte[] encrypt(Key key, byte[] b) throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException
|
||||||
|
{
|
||||||
Cipher hasher = Cipher.getInstance("RSA");
|
Cipher hasher = Cipher.getInstance("RSA");
|
||||||
hasher.init(Cipher.ENCRYPT_MODE, key);
|
hasher.init(Cipher.ENCRYPT_MODE, key);
|
||||||
return hasher.doFinal(b);
|
return hasher.doFinal(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] getShared(SecretKey key, PublicKey pubkey) throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
|
public static byte[] getShared(SecretKey key, PublicKey pubkey) throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException
|
||||||
|
{
|
||||||
Cipher cipher = Cipher.getInstance("RSA");
|
Cipher cipher = Cipher.getInstance("RSA");
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, pubkey);
|
cipher.init(Cipher.ENCRYPT_MODE, pubkey);
|
||||||
return cipher.doFinal(key.getEncoded());
|
return cipher.doFinal(key.getEncoded());
|
||||||
|
@ -3,47 +3,120 @@ package net.md_5.bungee;
|
|||||||
/**
|
/**
|
||||||
* Class to rewrite integers within packets.
|
* Class to rewrite integers within packets.
|
||||||
*/
|
*/
|
||||||
public class EntityMap {
|
public class EntityMap
|
||||||
|
{
|
||||||
|
|
||||||
public final static int[][] entityIds = new int[256][];
|
public final static int[][] entityIds = new int[256][];
|
||||||
|
|
||||||
static {
|
static
|
||||||
entityIds[0x05] = new int[]{1};
|
{
|
||||||
entityIds[0x07] = new int[]{1, 5};
|
entityIds[0x05] = new int[]
|
||||||
entityIds[0x11] = new int[]{1};
|
{
|
||||||
entityIds[0x12] = new int[]{1};
|
1
|
||||||
entityIds[0x13] = new int[]{1};
|
};
|
||||||
entityIds[0x14] = new int[]{1};
|
entityIds[0x07] = new int[]
|
||||||
entityIds[0x15] = new int[]{1};
|
{
|
||||||
entityIds[0x16] = new int[]{1, 5};
|
1, 5
|
||||||
entityIds[0x17] = new int[]{1};
|
};
|
||||||
entityIds[0x18] = new int[]{1};
|
entityIds[0x11] = new int[]
|
||||||
entityIds[0x19] = new int[]{1};
|
{
|
||||||
entityIds[0x1C] = new int[]{1};
|
1
|
||||||
entityIds[0x1E] = new int[]{1};
|
};
|
||||||
entityIds[0x1F] = new int[]{1};
|
entityIds[0x12] = new int[]
|
||||||
entityIds[0x20] = new int[]{1};
|
{
|
||||||
entityIds[0x21] = new int[]{1};
|
1
|
||||||
entityIds[0x22] = new int[]{1};
|
};
|
||||||
entityIds[0x26] = new int[]{1};
|
entityIds[0x13] = new int[]
|
||||||
entityIds[0x27] = new int[]{1, 5};
|
{
|
||||||
entityIds[0x28] = new int[]{1};
|
1
|
||||||
entityIds[0x47] = new int[]{1};
|
};
|
||||||
|
entityIds[0x14] = new int[]
|
||||||
|
{
|
||||||
|
1
|
||||||
|
};
|
||||||
|
entityIds[0x15] = new int[]
|
||||||
|
{
|
||||||
|
1
|
||||||
|
};
|
||||||
|
entityIds[0x16] = new int[]
|
||||||
|
{
|
||||||
|
1, 5
|
||||||
|
};
|
||||||
|
entityIds[0x17] = new int[]
|
||||||
|
{
|
||||||
|
1
|
||||||
|
};
|
||||||
|
entityIds[0x18] = new int[]
|
||||||
|
{
|
||||||
|
1
|
||||||
|
};
|
||||||
|
entityIds[0x19] = new int[]
|
||||||
|
{
|
||||||
|
1
|
||||||
|
};
|
||||||
|
entityIds[0x1C] = new int[]
|
||||||
|
{
|
||||||
|
1
|
||||||
|
};
|
||||||
|
entityIds[0x1E] = new int[]
|
||||||
|
{
|
||||||
|
1
|
||||||
|
};
|
||||||
|
entityIds[0x1F] = new int[]
|
||||||
|
{
|
||||||
|
1
|
||||||
|
};
|
||||||
|
entityIds[0x20] = new int[]
|
||||||
|
{
|
||||||
|
1
|
||||||
|
};
|
||||||
|
entityIds[0x21] = new int[]
|
||||||
|
{
|
||||||
|
1
|
||||||
|
};
|
||||||
|
entityIds[0x22] = new int[]
|
||||||
|
{
|
||||||
|
1
|
||||||
|
};
|
||||||
|
entityIds[0x26] = new int[]
|
||||||
|
{
|
||||||
|
1
|
||||||
|
};
|
||||||
|
entityIds[0x27] = new int[]
|
||||||
|
{
|
||||||
|
1, 5
|
||||||
|
};
|
||||||
|
entityIds[0x28] = new int[]
|
||||||
|
{
|
||||||
|
1
|
||||||
|
};
|
||||||
|
entityIds[0x47] = new int[]
|
||||||
|
{
|
||||||
|
1
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void rewrite(byte[] packet, int oldId, int newId) {
|
public static void rewrite(byte[] packet, int oldId, int newId)
|
||||||
|
{
|
||||||
int packetId = Util.getId(packet);
|
int packetId = Util.getId(packet);
|
||||||
if (packetId == 0x1D) { // bulk entity
|
if (packetId == 0x1D)
|
||||||
for (int pos = 2; pos < packet.length; pos += 4) {
|
{ // bulk entity
|
||||||
if (oldId == readInt(packet, pos)) {
|
for (int pos = 2; pos < packet.length; pos += 4)
|
||||||
|
{
|
||||||
|
if (oldId == readInt(packet, pos))
|
||||||
|
{
|
||||||
setInt(packet, pos, newId);
|
setInt(packet, pos, newId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else
|
||||||
|
{
|
||||||
int[] idArray = entityIds[packetId];
|
int[] idArray = entityIds[packetId];
|
||||||
if (idArray != null) {
|
if (idArray != null)
|
||||||
for (int pos : idArray) {
|
{
|
||||||
if (oldId == readInt(packet, pos)) {
|
for (int pos : idArray)
|
||||||
|
{
|
||||||
|
if (oldId == readInt(packet, pos))
|
||||||
|
{
|
||||||
setInt(packet, pos, newId);
|
setInt(packet, pos, newId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -51,14 +124,16 @@ public class EntityMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setInt(byte[] buf, int pos, int i) {
|
private static void setInt(byte[] buf, int pos, int i)
|
||||||
|
{
|
||||||
buf[pos] = (byte) (i >> 24);
|
buf[pos] = (byte) (i >> 24);
|
||||||
buf[pos + 1] = (byte) (i >> 16);
|
buf[pos + 1] = (byte) (i >> 16);
|
||||||
buf[pos + 2] = (byte) (i >> 8);
|
buf[pos + 2] = (byte) (i >> 8);
|
||||||
buf[pos + 3] = (byte) i;
|
buf[pos + 3] = (byte) i;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int readInt(byte[] buf, int pos) {
|
private static int readInt(byte[] buf, int pos)
|
||||||
|
{
|
||||||
return (((buf[pos] & 0xFF) << 24) | ((buf[pos + 1] & 0xFF) << 16) | ((buf[pos + 2] & 0xFF) << 8) | buf[pos + 3] & 0xFF);
|
return (((buf[pos] & 0xFF) << 24) | ((buf[pos + 1] & 0xFF) << 16) | ((buf[pos + 2] & 0xFF) << 8) | buf[pos + 3] & 0xFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@ import net.md_5.bungee.packet.PacketInputStream;
|
|||||||
*/
|
*/
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class GenericConnection {
|
public class GenericConnection
|
||||||
|
{
|
||||||
|
|
||||||
protected final Socket socket;
|
protected final Socket socket;
|
||||||
protected final PacketInputStream in;
|
protected final PacketInputStream in;
|
||||||
@ -26,24 +27,32 @@ public class GenericConnection {
|
|||||||
*
|
*
|
||||||
* @param reason to disconnect
|
* @param reason to disconnect
|
||||||
*/
|
*/
|
||||||
public void disconnect(String reason) {
|
public void disconnect(String reason)
|
||||||
if (socket.isClosed()) {
|
{
|
||||||
|
if (socket.isClosed())
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log("disconnected with " + reason);
|
log("disconnected with " + reason);
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
out.write(new PacketFFKick("[Proxy] " + reason).getPacket());
|
out.write(new PacketFFKick("[Proxy] " + reason).getPacket());
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex)
|
||||||
} finally {
|
{
|
||||||
try {
|
} finally
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
out.flush();
|
out.flush();
|
||||||
socket.close();
|
socket.close();
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void log(String message) {
|
public void log(String message)
|
||||||
|
{
|
||||||
$().info(socket.getInetAddress() + ((username == null) ? " " : " [" + username + "] ") + message);
|
$().info(socket.getInetAddress() + ((username == null) ? " " : " [" + username + "] ") + message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,30 +13,36 @@ import net.md_5.bungee.plugin.HandshakeEvent;
|
|||||||
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
|
||||||
|
{
|
||||||
|
|
||||||
private final Socket socket;
|
private final Socket socket;
|
||||||
private PacketInputStream in;
|
private PacketInputStream in;
|
||||||
private OutputStream out;
|
private OutputStream out;
|
||||||
|
|
||||||
public InitialHandler(Socket socket) throws IOException {
|
public InitialHandler(Socket socket) throws IOException
|
||||||
|
{
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
in = new PacketInputStream(socket.getInputStream());
|
in = new PacketInputStream(socket.getInputStream());
|
||||||
out = socket.getOutputStream();
|
out = socket.getOutputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run()
|
||||||
try {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
byte[] packet = in.readPacket();
|
byte[] packet = in.readPacket();
|
||||||
int id = Util.getId(packet);
|
int id = Util.getId(packet);
|
||||||
switch (id) {
|
switch (id)
|
||||||
|
{
|
||||||
case 0x02:
|
case 0x02:
|
||||||
Packet2Handshake handshake = new Packet2Handshake(packet);
|
Packet2Handshake handshake = new Packet2Handshake(packet);
|
||||||
// fire connect event
|
// fire connect event
|
||||||
HandshakeEvent event = new HandshakeEvent(handshake.username, socket.getInetAddress());
|
HandshakeEvent event = new HandshakeEvent(handshake.username, socket.getInetAddress());
|
||||||
BungeeCord.instance.pluginManager.onHandshake(event);
|
BungeeCord.instance.pluginManager.onHandshake(event);
|
||||||
if (event.isCancelled()) {
|
if (event.isCancelled())
|
||||||
|
{
|
||||||
throw new KickException(event.getCancelReason());
|
throw new KickException(event.getCancelReason());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +51,8 @@ public class InitialHandler implements Runnable {
|
|||||||
PacketFCEncryptionResponse response = new PacketFCEncryptionResponse(in.readPacket());
|
PacketFCEncryptionResponse response = new PacketFCEncryptionResponse(in.readPacket());
|
||||||
|
|
||||||
SecretKey shared = EncryptionUtil.getSecret(response, request);
|
SecretKey shared = EncryptionUtil.getSecret(response, request);
|
||||||
if (!EncryptionUtil.isAuthenticated(handshake.username, request.serverId, shared)) {
|
if (!EncryptionUtil.isAuthenticated(handshake.username, request.serverId, shared))
|
||||||
|
{
|
||||||
throw new KickException("Not authenticated with minecraft.net");
|
throw new KickException("Not authenticated with minecraft.net");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +61,8 @@ public class InitialHandler implements Runnable {
|
|||||||
out = new CipherOutputStream(socket.getOutputStream(), EncryptionUtil.getCipher(true, shared));
|
out = new CipherOutputStream(socket.getOutputStream(), EncryptionUtil.getCipher(true, shared));
|
||||||
|
|
||||||
int ciphId = Util.getId(in.readPacket());
|
int ciphId = Util.getId(in.readPacket());
|
||||||
if (ciphId != 0xCD) {
|
if (ciphId != 0xCD)
|
||||||
|
{
|
||||||
throw new KickException("Unable to receive encrypted client status");
|
throw new KickException("Unable to receive encrypted client status");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,22 +74,30 @@ public class InitialHandler implements Runnable {
|
|||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Wasn't ready for packet id " + Util.hex(id));
|
throw new IllegalArgumentException("Wasn't ready for packet id " + Util.hex(id));
|
||||||
}
|
}
|
||||||
} catch (KickException ex) {
|
} catch (KickException ex)
|
||||||
|
{
|
||||||
kick(ex.getMessage());
|
kick(ex.getMessage());
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
kick("[Proxy Error] " + Util.exception(ex));
|
kick("[Proxy Error] " + Util.exception(ex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void kick(String message) {
|
private void kick(String message)
|
||||||
try {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
out.write(new PacketFFKick(message).getPacket());
|
out.write(new PacketFFKick(message).getPacket());
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe)
|
||||||
} finally {
|
{
|
||||||
try {
|
} finally
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
out.flush();
|
out.flush();
|
||||||
socket.close();
|
socket.close();
|
||||||
} catch (IOException ioe2) {
|
} catch (IOException ioe2)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,11 @@ package net.md_5.bungee;
|
|||||||
* Exception, which when thrown will disconnect the player from the proxy with
|
* Exception, which when thrown will disconnect the player from the proxy with
|
||||||
* the specified message.
|
* the specified message.
|
||||||
*/
|
*/
|
||||||
public class KickException extends RuntimeException {
|
public class KickException extends RuntimeException
|
||||||
|
{
|
||||||
|
|
||||||
public KickException(String message) {
|
public KickException(String message)
|
||||||
|
{
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,27 +10,34 @@ import static net.md_5.bungee.Logger.$;
|
|||||||
/**
|
/**
|
||||||
* Thread to listen and dispatch incoming connections to the proxy.
|
* Thread to listen and dispatch incoming connections to the proxy.
|
||||||
*/
|
*/
|
||||||
public class ListenThread extends Thread {
|
public class ListenThread extends Thread
|
||||||
|
{
|
||||||
|
|
||||||
public final ServerSocket socket;
|
public final ServerSocket socket;
|
||||||
|
|
||||||
public ListenThread(InetSocketAddress addr) throws IOException {
|
public ListenThread(InetSocketAddress addr) throws IOException
|
||||||
|
{
|
||||||
super("Listen Thread");
|
super("Listen Thread");
|
||||||
socket = new ServerSocket();
|
socket = new ServerSocket();
|
||||||
socket.bind(addr);
|
socket.bind(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run()
|
||||||
while (BungeeCord.instance.isRunning) {
|
{
|
||||||
try {
|
while (BungeeCord.instance.isRunning)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
Socket client = socket.accept();
|
Socket client = socket.accept();
|
||||||
BungeeCord.instance.setSocketOptions(client);
|
BungeeCord.instance.setSocketOptions(client);
|
||||||
$().info(client.getInetAddress() + " has connected");
|
$().info(client.getInetAddress() + " has connected");
|
||||||
InitialHandler handler = new InitialHandler(client);
|
InitialHandler handler = new InitialHandler(client);
|
||||||
BungeeCord.instance.threadPool.submit(handler);
|
BungeeCord.instance.threadPool.submit(handler);
|
||||||
} catch (SocketException ex) {
|
} catch (SocketException ex)
|
||||||
} catch (IOException ex) {
|
{
|
||||||
|
} catch (IOException ex)
|
||||||
|
{
|
||||||
ex.printStackTrace(); // TODO
|
ex.printStackTrace(); // TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,30 +12,37 @@ import java.util.logging.LogRecord;
|
|||||||
/**
|
/**
|
||||||
* Logger to handle formatting and storage of the proxy's logger.
|
* Logger to handle formatting and storage of the proxy's logger.
|
||||||
*/
|
*/
|
||||||
public class Logger extends java.util.logging.Logger {
|
public class Logger extends java.util.logging.Logger
|
||||||
|
{
|
||||||
|
|
||||||
private static final Formatter formatter = new ConsoleLogFormatter();
|
private static final Formatter formatter = new ConsoleLogFormatter();
|
||||||
private static final Logger instance = new Logger();
|
private static final Logger instance = new Logger();
|
||||||
|
|
||||||
public Logger() {
|
public Logger()
|
||||||
|
{
|
||||||
super("RubberBand", null);
|
super("RubberBand", null);
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
FileHandler handler = new FileHandler("proxy.log", BungeeCord.instance.config.logNumLines, 1, true);
|
FileHandler handler = new FileHandler("proxy.log", BungeeCord.instance.config.logNumLines, 1, true);
|
||||||
handler.setFormatter(formatter);
|
handler.setFormatter(formatter);
|
||||||
addHandler(handler);
|
addHandler(handler);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex)
|
||||||
|
{
|
||||||
System.err.println("Could not register logger!");
|
System.err.println("Could not register logger!");
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void log(LogRecord record) {
|
public void log(LogRecord record)
|
||||||
|
{
|
||||||
super.log(record);
|
super.log(record);
|
||||||
String message = formatter.format(record);
|
String message = formatter.format(record);
|
||||||
if (record.getLevel() == Level.SEVERE || record.getLevel() == Level.WARNING) {
|
if (record.getLevel() == Level.SEVERE || record.getLevel() == Level.WARNING)
|
||||||
|
{
|
||||||
System.err.print(message);
|
System.err.print(message);
|
||||||
} else {
|
} else
|
||||||
|
{
|
||||||
System.out.print(message);
|
System.out.print(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,32 +52,41 @@ public class Logger extends java.util.logging.Logger {
|
|||||||
*
|
*
|
||||||
* @return the current logger instance
|
* @return the current logger instance
|
||||||
*/
|
*/
|
||||||
public static Logger $() {
|
public static Logger $()
|
||||||
|
{
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ConsoleLogFormatter extends Formatter {
|
public static class ConsoleLogFormatter extends Formatter
|
||||||
|
{
|
||||||
|
|
||||||
private SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
|
private SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String format(LogRecord logrecord) {
|
public String format(LogRecord logrecord)
|
||||||
|
{
|
||||||
StringBuilder formatted = new StringBuilder();
|
StringBuilder formatted = new StringBuilder();
|
||||||
|
|
||||||
formatted.append(formatter.format(logrecord.getMillis()));
|
formatted.append(formatter.format(logrecord.getMillis()));
|
||||||
Level level = logrecord.getLevel();
|
Level level = logrecord.getLevel();
|
||||||
|
|
||||||
if (level == Level.FINEST) {
|
if (level == Level.FINEST)
|
||||||
|
{
|
||||||
formatted.append(" [FINEST] ");
|
formatted.append(" [FINEST] ");
|
||||||
} else if (level == Level.FINER) {
|
} else if (level == Level.FINER)
|
||||||
|
{
|
||||||
formatted.append(" [FINER] ");
|
formatted.append(" [FINER] ");
|
||||||
} else if (level == Level.FINE) {
|
} else if (level == Level.FINE)
|
||||||
|
{
|
||||||
formatted.append(" [FINE] ");
|
formatted.append(" [FINE] ");
|
||||||
} else if (level == Level.INFO) {
|
} else if (level == Level.INFO)
|
||||||
|
{
|
||||||
formatted.append(" [INFO] ");
|
formatted.append(" [INFO] ");
|
||||||
} else if (level == Level.WARNING) {
|
} else if (level == Level.WARNING)
|
||||||
|
{
|
||||||
formatted.append(" [WARNING] ");
|
formatted.append(" [WARNING] ");
|
||||||
} else if (level == Level.SEVERE) {
|
} else if (level == Level.SEVERE)
|
||||||
|
{
|
||||||
formatted.append(" [SEVERE] ");
|
formatted.append(" [SEVERE] ");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +94,8 @@ public class Logger extends java.util.logging.Logger {
|
|||||||
formatted.append('\n');
|
formatted.append('\n');
|
||||||
Throwable throwable = logrecord.getThrown();
|
Throwable throwable = logrecord.getThrown();
|
||||||
|
|
||||||
if (throwable != null) {
|
if (throwable != null)
|
||||||
|
{
|
||||||
StringWriter writer = new StringWriter();
|
StringWriter writer = new StringWriter();
|
||||||
|
|
||||||
throwable.printStackTrace(new PrintWriter(writer));
|
throwable.printStackTrace(new PrintWriter(writer));
|
||||||
|
@ -10,7 +10,8 @@ import java.net.URLConnection;
|
|||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import static net.md_5.bungee.Logger.$;
|
import static net.md_5.bungee.Logger.$;
|
||||||
|
|
||||||
public class Metrics extends Thread {
|
public class Metrics extends Thread
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current revision number
|
* The current revision number
|
||||||
@ -29,16 +30,20 @@ public class Metrics extends Thread {
|
|||||||
*/
|
*/
|
||||||
private final static int PING_INTERVAL = 10;
|
private final static int PING_INTERVAL = 10;
|
||||||
|
|
||||||
public Metrics() {
|
public Metrics()
|
||||||
|
{
|
||||||
super("Metrics Gathering Thread");
|
super("Metrics Gathering Thread");
|
||||||
setDaemon(true);
|
setDaemon(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run()
|
||||||
|
{
|
||||||
boolean firstPost = true;
|
boolean firstPost = true;
|
||||||
while (true) {
|
while (true)
|
||||||
try {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
// We use the inverse of firstPost because if it is the first time we are posting,
|
// We use the inverse of firstPost because if it is the first time we are posting,
|
||||||
// it is not a interval ping, so it evaluates to FALSE
|
// it is not a interval ping, so it evaluates to FALSE
|
||||||
// Each time thereafter it will evaluate to TRUE, i.e PING!
|
// Each time thereafter it will evaluate to TRUE, i.e PING!
|
||||||
@ -47,12 +52,15 @@ public class Metrics extends Thread {
|
|||||||
// After the first post we set firstPost to false
|
// After the first post we set firstPost to false
|
||||||
// Each post thereafter will be a ping
|
// Each post thereafter will be a ping
|
||||||
firstPost = false;
|
firstPost = false;
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex)
|
||||||
|
{
|
||||||
$().info("[Metrics] " + ex.getMessage());
|
$().info("[Metrics] " + ex.getMessage());
|
||||||
}
|
}
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
sleep(PING_INTERVAL * 1000 * 60);
|
sleep(PING_INTERVAL * 1000 * 60);
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,7 +69,8 @@ public class Metrics extends Thread {
|
|||||||
/**
|
/**
|
||||||
* Generic method that posts a plugin to the metrics website
|
* Generic method that posts a plugin to the metrics website
|
||||||
*/
|
*/
|
||||||
private void postPlugin(boolean isPing) throws IOException {
|
private void postPlugin(boolean isPing) throws IOException
|
||||||
|
{
|
||||||
// Construct the post data
|
// Construct the post data
|
||||||
final StringBuilder data = new StringBuilder();
|
final StringBuilder data = new StringBuilder();
|
||||||
data.append(encode("guid")).append('=').append(encode(BungeeCord.instance.config.statsUuid));
|
data.append(encode("guid")).append('=').append(encode(BungeeCord.instance.config.statsUuid));
|
||||||
@ -71,7 +80,8 @@ public class Metrics extends Thread {
|
|||||||
encodeDataPair(data, "revision", String.valueOf(REVISION));
|
encodeDataPair(data, "revision", String.valueOf(REVISION));
|
||||||
|
|
||||||
// If we're pinging, append it
|
// If we're pinging, append it
|
||||||
if (isPing) {
|
if (isPing)
|
||||||
|
{
|
||||||
encodeDataPair(data, "ping", "true");
|
encodeDataPair(data, "ping", "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +96,8 @@ public class Metrics extends Thread {
|
|||||||
connection.setDoOutput(true);
|
connection.setDoOutput(true);
|
||||||
final BufferedReader reader;
|
final BufferedReader reader;
|
||||||
final String response;
|
final String response;
|
||||||
try (OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream())) {
|
try (OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream()))
|
||||||
|
{
|
||||||
writer.write(data.toString());
|
writer.write(data.toString());
|
||||||
writer.flush();
|
writer.flush();
|
||||||
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||||
@ -94,7 +105,8 @@ public class Metrics extends Thread {
|
|||||||
}
|
}
|
||||||
reader.close();
|
reader.close();
|
||||||
|
|
||||||
if (response == null || response.startsWith("ERR")) {
|
if (response == null || response.startsWith("ERR"))
|
||||||
|
{
|
||||||
throw new IOException(response); //Throw the exception
|
throw new IOException(response); //Throw the exception
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,7 +125,8 @@ public class Metrics extends Thread {
|
|||||||
* @param key the key value
|
* @param key the key value
|
||||||
* @param value the value
|
* @param value the value
|
||||||
*/
|
*/
|
||||||
private static void encodeDataPair(final StringBuilder buffer, final String key, final String value) throws UnsupportedEncodingException {
|
private static void encodeDataPair(final StringBuilder buffer, final String key, final String value) throws UnsupportedEncodingException
|
||||||
|
{
|
||||||
buffer.append('&').append(encode(key)).append('=').append(encode(value));
|
buffer.append('&').append(encode(key)).append('=').append(encode(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +136,8 @@ public class Metrics extends Thread {
|
|||||||
* @param text the text to encode
|
* @param text the text to encode
|
||||||
* @return the encoded text, as UTF-8
|
* @return the encoded text, as UTF-8
|
||||||
*/
|
*/
|
||||||
private static String encode(final String text) throws UnsupportedEncodingException {
|
private static String encode(final String text) throws UnsupportedEncodingException
|
||||||
|
{
|
||||||
return URLEncoder.encode(text, "UTF-8");
|
return URLEncoder.encode(text, "UTF-8");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.md_5.bungee;
|
package net.md_5.bungee;
|
||||||
|
|
||||||
public enum Permission {
|
public enum Permission
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Can access all commands.
|
* Can access all commands.
|
||||||
|
@ -4,19 +4,25 @@ package net.md_5.bungee;
|
|||||||
* Class to call the {@link Configuration#saveHosts() } method at 5 minute
|
* Class to call the {@link Configuration#saveHosts() } method at 5 minute
|
||||||
* intervals.
|
* intervals.
|
||||||
*/
|
*/
|
||||||
public class ReconnectSaveThread extends Thread {
|
public class ReconnectSaveThread extends Thread
|
||||||
|
{
|
||||||
|
|
||||||
public ReconnectSaveThread() {
|
public ReconnectSaveThread()
|
||||||
|
{
|
||||||
super("Location Save Thread");
|
super("Location Save Thread");
|
||||||
setPriority(Thread.MIN_PRIORITY);
|
setPriority(Thread.MIN_PRIORITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run()
|
||||||
while (BungeeCord.instance.isRunning) {
|
{
|
||||||
try {
|
while (BungeeCord.instance.isRunning)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
Thread.sleep(5 * 1000 * 60); // 5 minutes
|
Thread.sleep(5 * 1000 * 60); // 5 minutes
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
BungeeCord.instance.config.saveHosts();
|
BungeeCord.instance.config.saveHosts();
|
||||||
}
|
}
|
||||||
|
@ -19,19 +19,23 @@ import org.bouncycastle.crypto.io.CipherOutputStream;
|
|||||||
/**
|
/**
|
||||||
* Class representing a connection from the proxy to the server; ie upstream.
|
* Class representing a connection from the proxy to the server; ie upstream.
|
||||||
*/
|
*/
|
||||||
public class ServerConnection extends GenericConnection {
|
public class ServerConnection extends GenericConnection
|
||||||
|
{
|
||||||
|
|
||||||
public final String name;
|
public final String name;
|
||||||
public final Packet1Login loginPacket;
|
public final Packet1Login loginPacket;
|
||||||
|
|
||||||
public ServerConnection(String name, Socket socket, PacketInputStream in, OutputStream out, Packet1Login loginPacket) {
|
public ServerConnection(String name, Socket socket, PacketInputStream in, OutputStream out, Packet1Login loginPacket)
|
||||||
|
{
|
||||||
super(socket, in, out);
|
super(socket, in, out);
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.loginPacket = loginPacket;
|
this.loginPacket = loginPacket;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ServerConnection connect(String name, InetSocketAddress address, Packet2Handshake handshake, boolean retry) {
|
public static ServerConnection connect(String name, InetSocketAddress address, Packet2Handshake handshake, boolean retry)
|
||||||
try {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
Socket socket = new Socket();
|
Socket socket = new Socket();
|
||||||
socket.connect(address, BungeeCord.instance.config.timeout);
|
socket.connect(address, BungeeCord.instance.config.timeout);
|
||||||
BungeeCord.instance.setSocketOptions(socket);
|
BungeeCord.instance.setSocketOptions(socket);
|
||||||
@ -49,7 +53,8 @@ public class ServerConnection extends GenericConnection {
|
|||||||
out.write(response.getPacket());
|
out.write(response.getPacket());
|
||||||
|
|
||||||
int ciphId = Util.getId(in.readPacket());
|
int ciphId = Util.getId(in.readPacket());
|
||||||
if (ciphId != 0xFC) {
|
if (ciphId != 0xFC)
|
||||||
|
{
|
||||||
throw new RuntimeException("Server did not send encryption enable");
|
throw new RuntimeException("Server did not send encryption enable");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,20 +63,25 @@ public class ServerConnection extends GenericConnection {
|
|||||||
|
|
||||||
out.write(new PacketCDClientStatus((byte) 0).getPacket());
|
out.write(new PacketCDClientStatus((byte) 0).getPacket());
|
||||||
byte[] loginResponse = in.readPacket();
|
byte[] loginResponse = in.readPacket();
|
||||||
if (Util.getId(loginResponse) == 0xFF) {
|
if (Util.getId(loginResponse) == 0xFF)
|
||||||
|
{
|
||||||
throw new KickException("[Kicked] " + new PacketFFKick(loginResponse).message);
|
throw new KickException("[Kicked] " + new PacketFFKick(loginResponse).message);
|
||||||
}
|
}
|
||||||
Packet1Login login = new Packet1Login(loginResponse);
|
Packet1Login login = new Packet1Login(loginResponse);
|
||||||
out.write(new PacketFAPluginMessage("REGISTER", "RubberBand".getBytes()).getPacket());
|
out.write(new PacketFAPluginMessage("REGISTER", "RubberBand".getBytes()).getPacket());
|
||||||
|
|
||||||
return new ServerConnection(name, socket, in, out, login);
|
return new ServerConnection(name, socket, in, out, login);
|
||||||
} catch (KickException ex) {
|
} catch (KickException ex)
|
||||||
|
{
|
||||||
throw ex;
|
throw ex;
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
InetSocketAddress def = BungeeCord.instance.config.getServer(null);
|
InetSocketAddress def = BungeeCord.instance.config.getServer(null);
|
||||||
if (retry && !address.equals(def)) {
|
if (retry && !address.equals(def))
|
||||||
|
{
|
||||||
return connect(name, def, handshake, false);
|
return connect(name, def, handshake, false);
|
||||||
} else {
|
} else
|
||||||
|
{
|
||||||
throw new RuntimeException("Could not connect to target server");
|
throw new RuntimeException("Could not connect to target server");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package net.md_5.bungee;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
@ -19,7 +18,8 @@ import net.md_5.bungee.packet.Packet9Respawn;
|
|||||||
import net.md_5.bungee.packet.PacketFAPluginMessage;
|
import net.md_5.bungee.packet.PacketFAPluginMessage;
|
||||||
import net.md_5.bungee.packet.PacketInputStream;
|
import net.md_5.bungee.packet.PacketInputStream;
|
||||||
|
|
||||||
public class UserConnection extends GenericConnection implements CommandSender {
|
public class UserConnection extends GenericConnection implements CommandSender
|
||||||
|
{
|
||||||
|
|
||||||
public final Packet2Handshake handshake;
|
public final Packet2Handshake handshake;
|
||||||
public Queue<DefinedPacket> packetQueue = new ConcurrentLinkedQueue<>();
|
public Queue<DefinedPacket> packetQueue = new ConcurrentLinkedQueue<>();
|
||||||
@ -32,39 +32,48 @@ public class UserConnection extends GenericConnection implements CommandSender {
|
|||||||
private int serverEntityId;
|
private int serverEntityId;
|
||||||
private volatile boolean reconnecting;
|
private volatile boolean reconnecting;
|
||||||
|
|
||||||
public UserConnection(Socket socket, PacketInputStream in, OutputStream out, Packet2Handshake handshake) {
|
public UserConnection(Socket socket, PacketInputStream in, OutputStream out, Packet2Handshake handshake)
|
||||||
|
{
|
||||||
super(socket, in, out);
|
super(socket, in, out);
|
||||||
this.handshake = handshake;
|
this.handshake = handshake;
|
||||||
username = handshake.username;
|
username = handshake.username;
|
||||||
BungeeCord.instance.connections.put(username, this);
|
BungeeCord.instance.connections.put(username, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connect(String server) {
|
public void connect(String server)
|
||||||
|
{
|
||||||
InetSocketAddress addr = BungeeCord.instance.config.getServer(server);
|
InetSocketAddress addr = BungeeCord.instance.config.getServer(server);
|
||||||
connect(server, addr);
|
connect(server, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connect(String name, InetSocketAddress serverAddr) {
|
private void connect(String name, InetSocketAddress serverAddr)
|
||||||
try {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
reconnecting = true;
|
reconnecting = true;
|
||||||
|
|
||||||
if (server != null) {
|
if (server != null)
|
||||||
|
{
|
||||||
out.write(new Packet9Respawn((byte) 1, (byte) 0, (byte) 0, (short) 256, "DEFAULT").getPacket());
|
out.write(new Packet9Respawn((byte) 1, (byte) 0, (byte) 0, (short) 256, "DEFAULT").getPacket());
|
||||||
out.write(new Packet9Respawn((byte) -1, (byte) 0, (byte) 0, (short) 256, "DEFAULT").getPacket());
|
out.write(new Packet9Respawn((byte) -1, (byte) 0, (byte) 0, (short) 256, "DEFAULT").getPacket());
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerConnection newServer = ServerConnection.connect(name, serverAddr, handshake, server == null);
|
ServerConnection newServer = ServerConnection.connect(name, serverAddr, handshake, server == null);
|
||||||
if (server == null) {
|
if (server == null)
|
||||||
|
{
|
||||||
clientEntityId = newServer.loginPacket.entityId;
|
clientEntityId = newServer.loginPacket.entityId;
|
||||||
serverEntityId = newServer.loginPacket.entityId;
|
serverEntityId = newServer.loginPacket.entityId;
|
||||||
out.write(newServer.loginPacket.getPacket());
|
out.write(newServer.loginPacket.getPacket());
|
||||||
upBridge = new UpstreamBridge();
|
upBridge = new UpstreamBridge();
|
||||||
upBridge.start();
|
upBridge.start();
|
||||||
} else {
|
} else
|
||||||
try {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
downBridge.interrupt();
|
downBridge.interrupt();
|
||||||
downBridge.join();
|
downBridge.join();
|
||||||
} catch (InterruptedException ie) {
|
} catch (InterruptedException ie)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
server.disconnect("Quitting");
|
server.disconnect("Quitting");
|
||||||
@ -73,7 +82,8 @@ public class UserConnection extends GenericConnection implements CommandSender {
|
|||||||
serverEntityId = login.entityId;
|
serverEntityId = login.entityId;
|
||||||
out.write(new Packet9Respawn(login.dimension, login.difficulty, login.gameMode, (short) 256, login.levelType).getPacket());
|
out.write(new Packet9Respawn(login.dimension, login.difficulty, login.gameMode, (short) 256, login.levelType).getPacket());
|
||||||
out.write(new Packet46GameState((byte) 2, (byte) 0).getPacket());
|
out.write(new Packet46GameState((byte) 2, (byte) 0).getPacket());
|
||||||
if (heldItem != null) {
|
if (heldItem != null)
|
||||||
|
{
|
||||||
newServer.out.write(heldItem.getPacket());
|
newServer.out.write(heldItem.getPacket());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,100 +91,128 @@ public class UserConnection extends GenericConnection implements CommandSender {
|
|||||||
downBridge = new DownstreamBridge();
|
downBridge = new DownstreamBridge();
|
||||||
server = newServer;
|
server = newServer;
|
||||||
downBridge.start();
|
downBridge.start();
|
||||||
} catch (KickException ex) {
|
} catch (KickException ex)
|
||||||
|
{
|
||||||
destroySelf(ex.getMessage());
|
destroySelf(ex.getMessage());
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
destroySelf("Could not connect to server");
|
destroySelf("Could not connect to server");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SocketAddress getAddress() {
|
public SocketAddress getAddress()
|
||||||
|
{
|
||||||
return socket.getRemoteSocketAddress();
|
return socket.getRemoteSocketAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void destroySelf(String reason) {
|
private void destroySelf(String reason)
|
||||||
if (BungeeCord.instance.isRunning) {
|
{
|
||||||
|
if (BungeeCord.instance.isRunning)
|
||||||
|
{
|
||||||
BungeeCord.instance.connections.remove(username);
|
BungeeCord.instance.connections.remove(username);
|
||||||
}
|
}
|
||||||
disconnect(reason);
|
disconnect(reason);
|
||||||
if (server != null) {
|
if (server != null)
|
||||||
|
{
|
||||||
server.disconnect("Quitting");
|
server.disconnect("Quitting");
|
||||||
BungeeCord.instance.config.setServer(this, server.name);
|
BungeeCord.instance.config.setServer(this, server.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendMessage(String message) {
|
public void sendMessage(String message)
|
||||||
|
{
|
||||||
packetQueue.add(new Packet3Chat(message));
|
packetQueue.add(new Packet3Chat(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName()
|
||||||
|
{
|
||||||
return username;
|
return username;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class UpstreamBridge extends Thread {
|
private class UpstreamBridge extends Thread
|
||||||
|
{
|
||||||
|
|
||||||
public UpstreamBridge() {
|
public UpstreamBridge()
|
||||||
|
{
|
||||||
super("Upstream Bridge - " + username);
|
super("Upstream Bridge - " + username);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run()
|
||||||
while (!socket.isClosed()) {
|
{
|
||||||
try {
|
while (!socket.isClosed())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
byte[] packet = in.readPacket();
|
byte[] packet = in.readPacket();
|
||||||
boolean sendPacket = true;
|
boolean sendPacket = true;
|
||||||
|
|
||||||
int id = Util.getId(packet);
|
int id = Util.getId(packet);
|
||||||
if (id == 0x03) {
|
if (id == 0x03)
|
||||||
|
{
|
||||||
Packet3Chat chat = new Packet3Chat(packet);
|
Packet3Chat chat = new Packet3Chat(packet);
|
||||||
String message = chat.message;
|
String message = chat.message;
|
||||||
if (message.startsWith("/")) {
|
if (message.startsWith("/"))
|
||||||
|
{
|
||||||
sendPacket = !BungeeCord.instance.dispatchCommand(message.substring(1), UserConnection.this);
|
sendPacket = !BungeeCord.instance.dispatchCommand(message.substring(1), UserConnection.this);
|
||||||
}
|
}
|
||||||
} else if (id == 0x10) {
|
} else if (id == 0x10)
|
||||||
|
{
|
||||||
heldItem = new Packet10HeldItem(packet);
|
heldItem = new Packet10HeldItem(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityMap.rewrite(packet, clientEntityId, serverEntityId);
|
EntityMap.rewrite(packet, clientEntityId, serverEntityId);
|
||||||
if (sendPacket && !server.socket.isClosed()) {
|
if (sendPacket && !server.socket.isClosed())
|
||||||
|
{
|
||||||
server.out.write(packet);
|
server.out.write(packet);
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex)
|
||||||
|
{
|
||||||
destroySelf("Reached end of stream");
|
destroySelf("Reached end of stream");
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
destroySelf(Util.exception(ex));
|
destroySelf(Util.exception(ex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DownstreamBridge extends Thread {
|
private class DownstreamBridge extends Thread
|
||||||
|
{
|
||||||
|
|
||||||
public DownstreamBridge() {
|
public DownstreamBridge()
|
||||||
|
{
|
||||||
super("Downstream Bridge - " + username);
|
super("Downstream Bridge - " + username);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run()
|
||||||
try {
|
{
|
||||||
while (!reconnecting) {
|
try
|
||||||
|
{
|
||||||
|
while (!reconnecting)
|
||||||
|
{
|
||||||
byte[] packet = server.in.readPacket();
|
byte[] packet = server.in.readPacket();
|
||||||
|
|
||||||
int id = Util.getId(packet);
|
int id = Util.getId(packet);
|
||||||
if (id == 0xFA) {
|
if (id == 0xFA)
|
||||||
|
{
|
||||||
PacketFAPluginMessage message = new PacketFAPluginMessage(packet);
|
PacketFAPluginMessage message = new PacketFAPluginMessage(packet);
|
||||||
if (message.tag.equals("RubberBand")) {
|
if (message.tag.equals("RubberBand"))
|
||||||
|
{
|
||||||
String server = new String(message.data);
|
String server = new String(message.data);
|
||||||
connect(server);
|
connect(server);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!packetQueue.isEmpty()) {
|
while (!packetQueue.isEmpty())
|
||||||
|
{
|
||||||
DefinedPacket p = packetQueue.poll();
|
DefinedPacket p = packetQueue.poll();
|
||||||
if (p != null) {
|
if (p != null)
|
||||||
|
{
|
||||||
out.write(p.getPacket());
|
out.write(p.getPacket());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,7 +220,8 @@ public class UserConnection extends GenericConnection implements CommandSender {
|
|||||||
EntityMap.rewrite(packet, serverEntityId, clientEntityId);
|
EntityMap.rewrite(packet, serverEntityId, clientEntityId);
|
||||||
out.write(packet);
|
out.write(packet);
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
destroySelf(Util.exception(ex));
|
destroySelf(Util.exception(ex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,8 @@ import java.net.InetSocketAddress;
|
|||||||
/**
|
/**
|
||||||
* Series of utility classes to perform various operations.
|
* Series of utility classes to perform various operations.
|
||||||
*/
|
*/
|
||||||
public class Util {
|
public class Util
|
||||||
|
{
|
||||||
|
|
||||||
private static final int DEFAULT_PORT = 25565;
|
private static final int DEFAULT_PORT = 25565;
|
||||||
|
|
||||||
@ -15,10 +16,12 @@ public class Util {
|
|||||||
* @param hostline in the format of 'host:port'
|
* @param hostline in the format of 'host:port'
|
||||||
* @return the constructed hostname + port.
|
* @return the constructed hostname + port.
|
||||||
*/
|
*/
|
||||||
public static InetSocketAddress getAddr(String hostline) {
|
public static InetSocketAddress getAddr(String hostline)
|
||||||
|
{
|
||||||
String[] split = hostline.split(":");
|
String[] split = hostline.split(":");
|
||||||
int port = DEFAULT_PORT;
|
int port = DEFAULT_PORT;
|
||||||
if (split.length > 1) {
|
if (split.length > 1)
|
||||||
|
{
|
||||||
port = Integer.parseInt(split[1]);
|
port = Integer.parseInt(split[1]);
|
||||||
}
|
}
|
||||||
return new InetSocketAddress(split[0], port);
|
return new InetSocketAddress(split[0], port);
|
||||||
@ -31,7 +34,8 @@ public class Util {
|
|||||||
* @param b the array to read from
|
* @param b the array to read from
|
||||||
* @return the unsigned value of the first byte
|
* @return the unsigned value of the first byte
|
||||||
*/
|
*/
|
||||||
public static int getId(byte[] b) {
|
public static int getId(byte[] b)
|
||||||
|
{
|
||||||
return b[0] & 0xFF;
|
return b[0] & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,10 +46,13 @@ public class Util {
|
|||||||
* @param s the string to normalize
|
* @param s the string to normalize
|
||||||
* @return the normalized path
|
* @return the normalized path
|
||||||
*/
|
*/
|
||||||
public static String normalize(String s) {
|
public static String normalize(String s)
|
||||||
|
{
|
||||||
StringBuilder result = new StringBuilder();
|
StringBuilder result = new StringBuilder();
|
||||||
for (char c : s.toCharArray()) {
|
for (char c : s.toCharArray())
|
||||||
if (Character.isUpperCase(c)) {
|
{
|
||||||
|
if (Character.isUpperCase(c))
|
||||||
|
{
|
||||||
result.append("_");
|
result.append("_");
|
||||||
}
|
}
|
||||||
result.append(Character.toLowerCase(c));
|
result.append(Character.toLowerCase(c));
|
||||||
@ -59,7 +66,8 @@ public class Util {
|
|||||||
* @param i the integer to format
|
* @param i the integer to format
|
||||||
* @return the hex representation of the integer
|
* @return the hex representation of the integer
|
||||||
*/
|
*/
|
||||||
public static String hex(int i) {
|
public static String hex(int i)
|
||||||
|
{
|
||||||
return String.format("0x%02X", i);
|
return String.format("0x%02X", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +78,8 @@ public class Util {
|
|||||||
* @param t the {@link Throwable} to format.
|
* @param t the {@link Throwable} to format.
|
||||||
* @return a string representing information about the {@link Throwable}
|
* @return a string representing information about the {@link Throwable}
|
||||||
*/
|
*/
|
||||||
public static String exception(Throwable t) {
|
public static String exception(Throwable t)
|
||||||
|
{
|
||||||
return t.getClass().getSimpleName() + " : " + t.getMessage() + " @ " + t.getStackTrace()[0].getClassName() + ":" + t.getStackTrace()[0].getLineNumber();
|
return t.getClass().getSimpleName() + " : " + t.getMessage() + " @ " + t.getStackTrace()[0].getClassName() + ":" + t.getStackTrace()[0].getLineNumber();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,8 @@ import net.md_5.bungee.Permission;
|
|||||||
* Class which represents a proxy command. The {@link #execute(net.md_5.bungee.command.CommandSender, java.lang.String[])
|
* 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.
|
* } method will be called to dispatch the command.
|
||||||
*/
|
*/
|
||||||
public abstract class Command {
|
public abstract class Command
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute this command.
|
* Execute this command.
|
||||||
@ -18,7 +19,8 @@ public abstract class Command {
|
|||||||
*/
|
*/
|
||||||
public abstract void execute(CommandSender sender, String[] args);
|
public abstract void execute(CommandSender sender, String[] args);
|
||||||
|
|
||||||
public Permission getPermission(CommandSender sender) {
|
public Permission getPermission(CommandSender sender)
|
||||||
|
{
|
||||||
return BungeeCord.instance.config.getPermission(sender);
|
return BungeeCord.instance.config.getPermission(sender);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,25 +5,32 @@ import net.md_5.bungee.ChatColor;
|
|||||||
import net.md_5.bungee.Permission;
|
import net.md_5.bungee.Permission;
|
||||||
import net.md_5.bungee.UserConnection;
|
import net.md_5.bungee.UserConnection;
|
||||||
|
|
||||||
public class CommandAlert extends Command {
|
public class CommandAlert extends Command
|
||||||
|
{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(CommandSender sender, String[] args) {
|
public void execute(CommandSender sender, String[] args)
|
||||||
if (getPermission(sender) != Permission.ADMIN) {
|
{
|
||||||
|
if (getPermission(sender) != Permission.ADMIN)
|
||||||
|
{
|
||||||
sender.sendMessage(ChatColor.RED + "You do not have permission to execute this command!");
|
sender.sendMessage(ChatColor.RED + "You do not have permission to execute this command!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (args.length == 0) {
|
if (args.length == 0)
|
||||||
|
{
|
||||||
sender.sendMessage(ChatColor.RED + "Please follow this command by an announcement to make");
|
sender.sendMessage(ChatColor.RED + "Please follow this command by an announcement to make");
|
||||||
} else {
|
} else
|
||||||
|
{
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
builder.append(ChatColor.DARK_PURPLE);
|
builder.append(ChatColor.DARK_PURPLE);
|
||||||
builder.append(" [Alert] ");
|
builder.append(" [Alert] ");
|
||||||
for (String s : args) {
|
for (String s : args)
|
||||||
|
{
|
||||||
builder.append(s);
|
builder.append(s);
|
||||||
}
|
}
|
||||||
String message = builder.toString();
|
String message = builder.toString();
|
||||||
for (UserConnection con : BungeeCord.instance.connections.values()) {
|
for (UserConnection con : BungeeCord.instance.connections.values())
|
||||||
|
{
|
||||||
con.sendMessage(message.toString());
|
con.sendMessage(message.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,13 +7,17 @@ import net.md_5.bungee.Permission;
|
|||||||
/**
|
/**
|
||||||
* Command to terminate the proxy instance. May only be used by the console.
|
* Command to terminate the proxy instance. May only be used by the console.
|
||||||
*/
|
*/
|
||||||
public class CommandEnd extends Command {
|
public class CommandEnd extends Command
|
||||||
|
{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(CommandSender sender, String[] args) {
|
public void execute(CommandSender sender, String[] args)
|
||||||
if (getPermission(sender) != Permission.ADMIN) {
|
{
|
||||||
|
if (getPermission(sender) != Permission.ADMIN)
|
||||||
|
{
|
||||||
sender.sendMessage(ChatColor.RED + "You do not have permission to use this command");
|
sender.sendMessage(ChatColor.RED + "You do not have permission to use this command");
|
||||||
} else {
|
} else
|
||||||
|
{
|
||||||
BungeeCord.instance.stop();
|
BungeeCord.instance.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,22 +5,28 @@ import net.md_5.bungee.ChatColor;
|
|||||||
import net.md_5.bungee.Permission;
|
import net.md_5.bungee.Permission;
|
||||||
import net.md_5.bungee.UserConnection;
|
import net.md_5.bungee.UserConnection;
|
||||||
|
|
||||||
public class CommandIP extends Command {
|
public class CommandIP extends Command
|
||||||
|
{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(CommandSender sender, String[] args) {
|
public void execute(CommandSender sender, String[] args)
|
||||||
if (getPermission(sender) != Permission.ADMIN) {
|
{
|
||||||
|
if (getPermission(sender) != Permission.ADMIN)
|
||||||
|
{
|
||||||
sender.sendMessage(ChatColor.RED + "You do not have permission to use this command");
|
sender.sendMessage(ChatColor.RED + "You do not have permission to use this command");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (args.length < 1) {
|
if (args.length < 1)
|
||||||
|
{
|
||||||
sender.sendMessage(ChatColor.RED + "Please follow this command by a user name");
|
sender.sendMessage(ChatColor.RED + "Please follow this command by a user name");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
UserConnection user = BungeeCord.instance.connections.get(args[0]);
|
UserConnection user = BungeeCord.instance.connections.get(args[0]);
|
||||||
if (user == null) {
|
if (user == null)
|
||||||
|
{
|
||||||
sender.sendMessage(ChatColor.RED + "That user is not online");
|
sender.sendMessage(ChatColor.RED + "That user is not online");
|
||||||
} else {
|
} else
|
||||||
|
{
|
||||||
sender.sendMessage(ChatColor.BLUE + "IP of " + args[0] + " is " + user.getAddress());
|
sender.sendMessage(ChatColor.BLUE + "IP of " + args[0] + " is " + user.getAddress());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,15 +8,19 @@ import net.md_5.bungee.UserConnection;
|
|||||||
/**
|
/**
|
||||||
* Command to list all players connected to the proxy.
|
* Command to list all players connected to the proxy.
|
||||||
*/
|
*/
|
||||||
public class CommandList extends Command {
|
public class CommandList extends Command
|
||||||
|
{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(CommandSender sender, String[] args) {
|
public void execute(CommandSender sender, String[] args)
|
||||||
|
{
|
||||||
StringBuilder users = new StringBuilder();
|
StringBuilder users = new StringBuilder();
|
||||||
Collection<UserConnection> connections = BungeeCord.instance.connections.values();
|
Collection<UserConnection> connections = BungeeCord.instance.connections.values();
|
||||||
|
|
||||||
for (UserConnection con : connections) {
|
for (UserConnection con : connections)
|
||||||
switch (getPermission(con)) {
|
{
|
||||||
|
switch (getPermission(con))
|
||||||
|
{
|
||||||
case ADMIN:
|
case ADMIN:
|
||||||
users.append(ChatColor.RED);
|
users.append(ChatColor.RED);
|
||||||
break;
|
break;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.md_5.bungee.command;
|
package net.md_5.bungee.command;
|
||||||
|
|
||||||
public interface CommandSender {
|
public interface CommandSender
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a message to the client at the earliest available opportunity.
|
* Sends a message to the client at the earliest available opportunity.
|
||||||
|
@ -8,28 +8,36 @@ import net.md_5.bungee.UserConnection;
|
|||||||
/**
|
/**
|
||||||
* Command to list and switch a player between available servers.
|
* Command to list and switch a player between available servers.
|
||||||
*/
|
*/
|
||||||
public class CommandServer extends Command {
|
public class CommandServer extends Command
|
||||||
|
{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(CommandSender sender, String[] args) {
|
public void execute(CommandSender sender, String[] args)
|
||||||
if (!(sender instanceof UserConnection)) {
|
{
|
||||||
|
if (!(sender instanceof UserConnection))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
UserConnection con = (UserConnection) sender;
|
UserConnection con = (UserConnection) sender;
|
||||||
Collection<String> servers = BungeeCord.instance.config.servers.keySet();
|
Collection<String> servers = BungeeCord.instance.config.servers.keySet();
|
||||||
if (args.length <= 0) {
|
if (args.length <= 0)
|
||||||
|
{
|
||||||
StringBuilder serverList = new StringBuilder();
|
StringBuilder serverList = new StringBuilder();
|
||||||
for (String server : servers) {
|
for (String server : servers)
|
||||||
|
{
|
||||||
serverList.append(server);
|
serverList.append(server);
|
||||||
serverList.append(", ");
|
serverList.append(", ");
|
||||||
}
|
}
|
||||||
serverList.setLength(serverList.length() - 2);
|
serverList.setLength(serverList.length() - 2);
|
||||||
con.sendMessage(ChatColor.GOLD + "You may connect to the following servers at this time: " + serverList.toString());
|
con.sendMessage(ChatColor.GOLD + "You may connect to the following servers at this time: " + serverList.toString());
|
||||||
} else {
|
} else
|
||||||
|
{
|
||||||
String server = args[0];
|
String server = args[0];
|
||||||
if (!servers.contains(server)) {
|
if (!servers.contains(server))
|
||||||
|
{
|
||||||
con.sendMessage(ChatColor.RED + "The specified server does not exist");
|
con.sendMessage(ChatColor.RED + "The specified server does not exist");
|
||||||
} else {
|
} else
|
||||||
|
{
|
||||||
con.connect(server);
|
con.connect(server);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,17 +5,20 @@ import net.md_5.bungee.ChatColor;
|
|||||||
/**
|
/**
|
||||||
* Command sender representing the proxy console.
|
* Command sender representing the proxy console.
|
||||||
*/
|
*/
|
||||||
public class ConsoleCommandSender implements CommandSender {
|
public class ConsoleCommandSender implements CommandSender
|
||||||
|
{
|
||||||
|
|
||||||
public static final ConsoleCommandSender instance = new ConsoleCommandSender();
|
public static final ConsoleCommandSender instance = new ConsoleCommandSender();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendMessage(String message) {
|
public void sendMessage(String message)
|
||||||
|
{
|
||||||
System.out.println(ChatColor.stripColor(message));
|
System.out.println(ChatColor.stripColor(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName()
|
||||||
|
{
|
||||||
return "CONSOLE";
|
return "CONSOLE";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,11 @@ import net.md_5.bungee.Util;
|
|||||||
* subclasses can read and write to the backing byte array which can be
|
* subclasses can read and write to the backing byte array which can be
|
||||||
* retrieved via the {@link #getPacket()} method.
|
* retrieved via the {@link #getPacket()} method.
|
||||||
*/
|
*/
|
||||||
public abstract class DefinedPacket implements DataInput, DataOutput {
|
public abstract class DefinedPacket implements DataInput, DataOutput
|
||||||
|
{
|
||||||
|
|
||||||
private interface Overriden {
|
private interface Overriden
|
||||||
|
{
|
||||||
|
|
||||||
void readUTF();
|
void readUTF();
|
||||||
|
|
||||||
@ -34,16 +36,19 @@ public abstract class DefinedPacket implements DataInput, DataOutput {
|
|||||||
*/
|
*/
|
||||||
private byte[] packet;
|
private byte[] packet;
|
||||||
|
|
||||||
public DefinedPacket(int id, byte[] buf) {
|
public DefinedPacket(int id, byte[] buf)
|
||||||
|
{
|
||||||
in = ByteStreams.newDataInput(buf);
|
in = ByteStreams.newDataInput(buf);
|
||||||
if (readUnsignedByte() != id) {
|
if (readUnsignedByte() != id)
|
||||||
|
{
|
||||||
throw new IllegalArgumentException("Wasn't expecting packet id " + Util.hex(id));
|
throw new IllegalArgumentException("Wasn't expecting packet id " + Util.hex(id));
|
||||||
}
|
}
|
||||||
this.id = id;
|
this.id = id;
|
||||||
packet = buf;
|
packet = buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DefinedPacket(int id) {
|
public DefinedPacket(int id)
|
||||||
|
{
|
||||||
out = ByteStreams.newDataOutput();
|
out = ByteStreams.newDataOutput();
|
||||||
this.id = id;
|
this.id = id;
|
||||||
writeByte(id);
|
writeByte(id);
|
||||||
@ -55,32 +60,38 @@ public abstract class DefinedPacket implements DataInput, DataOutput {
|
|||||||
* @return the bytes which make up this packet, either the original byte
|
* @return the bytes which make up this packet, either the original byte
|
||||||
* array or the newly written one.
|
* array or the newly written one.
|
||||||
*/
|
*/
|
||||||
public byte[] getPacket() {
|
public byte[] getPacket()
|
||||||
|
{
|
||||||
return packet == null ? out.toByteArray() : packet;
|
return packet == null ? out.toByteArray() : packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeUTF(String s) {
|
public void writeUTF(String s)
|
||||||
|
{
|
||||||
writeShort(s.length());
|
writeShort(s.length());
|
||||||
writeChars(s);
|
writeChars(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String readUTF() {
|
public String readUTF()
|
||||||
|
{
|
||||||
short len = readShort();
|
short len = readShort();
|
||||||
char[] chars = new char[len];
|
char[] chars = new char[len];
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
chars[i] = this.readChar();
|
chars[i] = this.readChar();
|
||||||
}
|
}
|
||||||
return new String(chars);
|
return new String(chars);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeArray(byte[] b) {
|
public void writeArray(byte[] b)
|
||||||
|
{
|
||||||
writeShort(b.length);
|
writeShort(b.length);
|
||||||
write(b);
|
write(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] readArray() {
|
public byte[] readArray()
|
||||||
|
{
|
||||||
short len = readShort();
|
short len = readShort();
|
||||||
byte[] ret = new byte[len];
|
byte[] ret = new byte[len];
|
||||||
readFully(ret);
|
readFully(ret);
|
||||||
|
@ -5,16 +5,19 @@ import lombok.ToString;
|
|||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
public class Packet10HeldItem extends DefinedPacket {
|
public class Packet10HeldItem extends DefinedPacket
|
||||||
|
{
|
||||||
|
|
||||||
public short slot;
|
public short slot;
|
||||||
|
|
||||||
public Packet10HeldItem(short slot) {
|
public Packet10HeldItem(short slot)
|
||||||
|
{
|
||||||
super(0x10);
|
super(0x10);
|
||||||
writeShort(slot);
|
writeShort(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Packet10HeldItem(byte[] buf) {
|
public Packet10HeldItem(byte[] buf)
|
||||||
|
{
|
||||||
super(0x10, buf);
|
super(0x10, buf);
|
||||||
this.slot = readShort();
|
this.slot = readShort();
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,8 @@ import lombok.ToString;
|
|||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
public class Packet1Login extends DefinedPacket {
|
public class Packet1Login extends DefinedPacket
|
||||||
|
{
|
||||||
|
|
||||||
public int entityId;
|
public int entityId;
|
||||||
public String levelType;
|
public String levelType;
|
||||||
@ -15,7 +16,8 @@ public class Packet1Login extends DefinedPacket {
|
|||||||
public byte unused;
|
public byte unused;
|
||||||
public byte maxPlayers;
|
public byte maxPlayers;
|
||||||
|
|
||||||
public Packet1Login(int entityId, String levelType, byte gameMode, byte dimension, byte difficulty, byte unused, byte maxPlayers) {
|
public Packet1Login(int entityId, String levelType, byte gameMode, byte dimension, byte difficulty, byte unused, byte maxPlayers)
|
||||||
|
{
|
||||||
super(0x01);
|
super(0x01);
|
||||||
writeInt(entityId);
|
writeInt(entityId);
|
||||||
writeUTF(levelType);
|
writeUTF(levelType);
|
||||||
@ -26,7 +28,8 @@ public class Packet1Login extends DefinedPacket {
|
|||||||
writeByte(maxPlayers);
|
writeByte(maxPlayers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Packet1Login(byte[] buf) {
|
public Packet1Login(byte[] buf)
|
||||||
|
{
|
||||||
super(0x01, buf);
|
super(0x01, buf);
|
||||||
this.entityId = readInt();
|
this.entityId = readInt();
|
||||||
this.levelType = readUTF();
|
this.levelType = readUTF();
|
||||||
|
@ -5,14 +5,16 @@ import lombok.ToString;
|
|||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
public class Packet2Handshake extends DefinedPacket {
|
public class Packet2Handshake extends DefinedPacket
|
||||||
|
{
|
||||||
|
|
||||||
public byte procolVersion;
|
public byte procolVersion;
|
||||||
public String username;
|
public String username;
|
||||||
public String host;
|
public String host;
|
||||||
public int port;
|
public int port;
|
||||||
|
|
||||||
public Packet2Handshake(byte protocolVersion, String username, String host, int port) {
|
public Packet2Handshake(byte protocolVersion, String username, String host, int port)
|
||||||
|
{
|
||||||
super(0x02);
|
super(0x02);
|
||||||
writeByte(protocolVersion);
|
writeByte(protocolVersion);
|
||||||
writeUTF(username);
|
writeUTF(username);
|
||||||
@ -20,7 +22,8 @@ public class Packet2Handshake extends DefinedPacket {
|
|||||||
writeInt(port);
|
writeInt(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Packet2Handshake(byte[] buf) {
|
public Packet2Handshake(byte[] buf)
|
||||||
|
{
|
||||||
super(0x02, buf);
|
super(0x02, buf);
|
||||||
this.procolVersion = readByte();
|
this.procolVersion = readByte();
|
||||||
this.username = readUTF();
|
this.username = readUTF();
|
||||||
|
@ -5,16 +5,19 @@ import lombok.ToString;
|
|||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
public class Packet3Chat extends DefinedPacket {
|
public class Packet3Chat extends DefinedPacket
|
||||||
|
{
|
||||||
|
|
||||||
public String message;
|
public String message;
|
||||||
|
|
||||||
public Packet3Chat(String message) {
|
public Packet3Chat(String message)
|
||||||
|
{
|
||||||
super(0x03);
|
super(0x03);
|
||||||
writeUTF(message);
|
writeUTF(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Packet3Chat(byte[] buf) {
|
public Packet3Chat(byte[] buf)
|
||||||
|
{
|
||||||
super(0x03, buf);
|
super(0x03, buf);
|
||||||
this.message = readUTF();
|
this.message = readUTF();
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,8 @@ import lombok.ToString;
|
|||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
public class Packet46GameState extends DefinedPacket {
|
public class Packet46GameState extends DefinedPacket
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update game state. When sent with a state of 2, rain will cease.
|
* Update game state. When sent with a state of 2, rain will cease.
|
||||||
@ -13,7 +14,8 @@ public class Packet46GameState extends DefinedPacket {
|
|||||||
* @param state the new game state
|
* @param state the new game state
|
||||||
* @param mode the new game mode. Used when state == 3.
|
* @param mode the new game mode. Used when state == 3.
|
||||||
*/
|
*/
|
||||||
public Packet46GameState(byte state, byte mode) {
|
public Packet46GameState(byte state, byte mode)
|
||||||
|
{
|
||||||
super(0x46);
|
super(0x46);
|
||||||
writeByte(state);
|
writeByte(state);
|
||||||
writeByte(mode);
|
writeByte(mode);
|
||||||
|
@ -5,7 +5,8 @@ import lombok.ToString;
|
|||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
public class Packet9Respawn extends DefinedPacket {
|
public class Packet9Respawn extends DefinedPacket
|
||||||
|
{
|
||||||
|
|
||||||
public int dimension;
|
public int dimension;
|
||||||
public byte difficulty;
|
public byte difficulty;
|
||||||
@ -13,7 +14,8 @@ public class Packet9Respawn extends DefinedPacket {
|
|||||||
public short worldHeight;
|
public short worldHeight;
|
||||||
public String levelType;
|
public String levelType;
|
||||||
|
|
||||||
public Packet9Respawn(int dimension, byte difficulty, byte gameMode, short worldHeight, String levelType) {
|
public Packet9Respawn(int dimension, byte difficulty, byte gameMode, short worldHeight, String levelType)
|
||||||
|
{
|
||||||
super(0x09);
|
super(0x09);
|
||||||
writeInt(dimension);
|
writeInt(dimension);
|
||||||
writeByte(difficulty);
|
writeByte(difficulty);
|
||||||
@ -22,7 +24,8 @@ public class Packet9Respawn extends DefinedPacket {
|
|||||||
writeUTF(levelType);
|
writeUTF(levelType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Packet9Respawn(byte[] buf) {
|
public Packet9Respawn(byte[] buf)
|
||||||
|
{
|
||||||
super(0x09, buf);
|
super(0x09, buf);
|
||||||
this.dimension = readInt();
|
this.dimension = readInt();
|
||||||
this.difficulty = readByte();
|
this.difficulty = readByte();
|
||||||
|
@ -5,14 +5,16 @@ import lombok.ToString;
|
|||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
public class PacketCDClientStatus extends DefinedPacket {
|
public class PacketCDClientStatus extends DefinedPacket
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sent from the client to the server upon respawn,
|
* Sent from the client to the server upon respawn,
|
||||||
*
|
*
|
||||||
* @param payload 0 if initial spawn, 1 if respawn after death.
|
* @param payload 0 if initial spawn, 1 if respawn after death.
|
||||||
*/
|
*/
|
||||||
public PacketCDClientStatus(byte payload) {
|
public PacketCDClientStatus(byte payload)
|
||||||
|
{
|
||||||
super(0xCD);
|
super(0xCD);
|
||||||
writeByte(payload);
|
writeByte(payload);
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,14 @@ import lombok.ToString;
|
|||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
public class PacketFAPluginMessage extends DefinedPacket {
|
public class PacketFAPluginMessage extends DefinedPacket
|
||||||
|
{
|
||||||
|
|
||||||
public String tag;
|
public String tag;
|
||||||
public byte[] data;
|
public byte[] data;
|
||||||
|
|
||||||
public PacketFAPluginMessage(String tag, byte[] data) {
|
public PacketFAPluginMessage(String tag, byte[] data)
|
||||||
|
{
|
||||||
super(0xFA);
|
super(0xFA);
|
||||||
writeUTF(tag);
|
writeUTF(tag);
|
||||||
writeArray(data);
|
writeArray(data);
|
||||||
@ -18,7 +20,8 @@ public class PacketFAPluginMessage extends DefinedPacket {
|
|||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PacketFAPluginMessage(byte[] buf) {
|
public PacketFAPluginMessage(byte[] buf)
|
||||||
|
{
|
||||||
super(0xFA, buf);
|
super(0xFA, buf);
|
||||||
this.tag = readUTF();
|
this.tag = readUTF();
|
||||||
this.data = readArray();
|
this.data = readArray();
|
||||||
|
@ -5,24 +5,28 @@ import lombok.ToString;
|
|||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
public class PacketFCEncryptionResponse extends DefinedPacket {
|
public class PacketFCEncryptionResponse extends DefinedPacket
|
||||||
|
{
|
||||||
|
|
||||||
public byte[] sharedSecret;
|
public byte[] sharedSecret;
|
||||||
public byte[] verifyToken;
|
public byte[] verifyToken;
|
||||||
|
|
||||||
public PacketFCEncryptionResponse() {
|
public PacketFCEncryptionResponse()
|
||||||
|
{
|
||||||
super(0xFC);
|
super(0xFC);
|
||||||
writeArray(new byte[0]);
|
writeArray(new byte[0]);
|
||||||
writeArray(new byte[0]);
|
writeArray(new byte[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PacketFCEncryptionResponse(byte[] sharedSecret, byte[] verifyToken) {
|
public PacketFCEncryptionResponse(byte[] sharedSecret, byte[] verifyToken)
|
||||||
|
{
|
||||||
super(0xFC);
|
super(0xFC);
|
||||||
writeArray(sharedSecret);
|
writeArray(sharedSecret);
|
||||||
writeArray(verifyToken);
|
writeArray(verifyToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PacketFCEncryptionResponse(byte[] buf) {
|
public PacketFCEncryptionResponse(byte[] buf)
|
||||||
|
{
|
||||||
super(0xFC, buf);
|
super(0xFC, buf);
|
||||||
this.sharedSecret = readArray();
|
this.sharedSecret = readArray();
|
||||||
this.verifyToken = readArray();
|
this.verifyToken = readArray();
|
||||||
|
@ -5,13 +5,15 @@ import lombok.ToString;
|
|||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
public class PacketFDEncryptionRequest extends DefinedPacket {
|
public class PacketFDEncryptionRequest extends DefinedPacket
|
||||||
|
{
|
||||||
|
|
||||||
public String serverId;
|
public String serverId;
|
||||||
public byte[] publicKey;
|
public byte[] publicKey;
|
||||||
public byte[] verifyToken;
|
public byte[] verifyToken;
|
||||||
|
|
||||||
public PacketFDEncryptionRequest(String serverId, byte[] publicKey, byte[] verifyToken) {
|
public PacketFDEncryptionRequest(String serverId, byte[] publicKey, byte[] verifyToken)
|
||||||
|
{
|
||||||
super(0xFD);
|
super(0xFD);
|
||||||
writeUTF(serverId);
|
writeUTF(serverId);
|
||||||
writeArray(publicKey);
|
writeArray(publicKey);
|
||||||
@ -21,7 +23,8 @@ public class PacketFDEncryptionRequest extends DefinedPacket {
|
|||||||
this.verifyToken = verifyToken;
|
this.verifyToken = verifyToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PacketFDEncryptionRequest(byte[] buf) {
|
public PacketFDEncryptionRequest(byte[] buf)
|
||||||
|
{
|
||||||
super(0xFD, buf);
|
super(0xFD, buf);
|
||||||
serverId = readUTF();
|
serverId = readUTF();
|
||||||
publicKey = readArray();
|
publicKey = readArray();
|
||||||
|
@ -5,16 +5,19 @@ import lombok.ToString;
|
|||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
public class PacketFFKick extends DefinedPacket {
|
public class PacketFFKick extends DefinedPacket
|
||||||
|
{
|
||||||
|
|
||||||
public String message;
|
public String message;
|
||||||
|
|
||||||
public PacketFFKick(String message) {
|
public PacketFFKick(String message)
|
||||||
|
{
|
||||||
super(0xFF);
|
super(0xFF);
|
||||||
writeUTF(message);
|
writeUTF(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PacketFFKick(byte[] buf) {
|
public PacketFFKick(byte[] buf)
|
||||||
|
{
|
||||||
super(0xFF, buf);
|
super(0xFF, buf);
|
||||||
this.message = readUTF();
|
this.message = readUTF();
|
||||||
}
|
}
|
||||||
|
@ -12,12 +12,14 @@ import net.minecraft.server.Packet;
|
|||||||
* A specialized input stream to parse packets using the Mojang packet
|
* A specialized input stream to parse packets using the Mojang packet
|
||||||
* definitions and then return them as a byte array.
|
* definitions and then return them as a byte array.
|
||||||
*/
|
*/
|
||||||
public class PacketInputStream {
|
public class PacketInputStream
|
||||||
|
{
|
||||||
|
|
||||||
private final DataInputStream dataInput;
|
private final DataInputStream dataInput;
|
||||||
private final TrackingInputStream tracker;
|
private final TrackingInputStream tracker;
|
||||||
|
|
||||||
public PacketInputStream(InputStream in) {
|
public PacketInputStream(InputStream in)
|
||||||
|
{
|
||||||
tracker = new TrackingInputStream(in);
|
tracker = new TrackingInputStream(in);
|
||||||
dataInput = new DataInputStream(tracker);
|
dataInput = new DataInputStream(tracker);
|
||||||
}
|
}
|
||||||
@ -28,14 +30,17 @@ public class PacketInputStream {
|
|||||||
* @return the read packet
|
* @return the read packet
|
||||||
* @throws IOException when the underlying input stream throws an exception
|
* @throws IOException when the underlying input stream throws an exception
|
||||||
*/
|
*/
|
||||||
public byte[] readPacket() throws IOException {
|
public byte[] readPacket() throws IOException
|
||||||
|
{
|
||||||
tracker.out.reset();
|
tracker.out.reset();
|
||||||
int id = tracker.read();
|
int id = tracker.read();
|
||||||
if (id == -1) {
|
if (id == -1)
|
||||||
|
{
|
||||||
throw new EOFException();
|
throw new EOFException();
|
||||||
}
|
}
|
||||||
Packet codec = VanillaPackets.packets[id];
|
Packet codec = VanillaPackets.packets[id];
|
||||||
if (codec == null) {
|
if (codec == null)
|
||||||
|
{
|
||||||
throw new RuntimeException("No Packet id: " + Util.hex(id));
|
throw new RuntimeException("No Packet id: " + Util.hex(id));
|
||||||
}
|
}
|
||||||
codec.a(dataInput);
|
codec.a(dataInput);
|
||||||
@ -47,17 +52,20 @@ public class PacketInputStream {
|
|||||||
* Input stream which will wrap another stream and copy all bytes read to a
|
* Input stream which will wrap another stream and copy all bytes read to a
|
||||||
* {@link ByteArrayOutputStream}.
|
* {@link ByteArrayOutputStream}.
|
||||||
*/
|
*/
|
||||||
private class TrackingInputStream extends InputStream {
|
private class TrackingInputStream extends InputStream
|
||||||
|
{
|
||||||
|
|
||||||
private final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
private final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
private final InputStream wrapped;
|
private final InputStream wrapped;
|
||||||
|
|
||||||
public TrackingInputStream(InputStream wrapped) {
|
public TrackingInputStream(InputStream wrapped)
|
||||||
|
{
|
||||||
this.wrapped = wrapped;
|
this.wrapped = wrapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read() throws IOException {
|
public int read() throws IOException
|
||||||
|
{
|
||||||
int ret = wrapped.read();
|
int ret = wrapped.read();
|
||||||
out.write(ret);
|
out.write(ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -83,7 +83,8 @@ import net.minecraft.server.Packet9Respawn;
|
|||||||
/**
|
/**
|
||||||
* Class containing instances of all Vanilla Minecraft packets.
|
* Class containing instances of all Vanilla Minecraft packets.
|
||||||
*/
|
*/
|
||||||
public class VanillaPackets {
|
public class VanillaPackets
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array of packet instances ordered by packet id.
|
* Array of packet instances ordered by packet id.
|
||||||
@ -96,15 +97,19 @@ public class VanillaPackets {
|
|||||||
* @param id of the packet to add
|
* @param id of the packet to add
|
||||||
* @param clazz class of the packet to add
|
* @param clazz class of the packet to add
|
||||||
*/
|
*/
|
||||||
private static void map(int id, Class<? extends Packet> clazz) {
|
private static void map(int id, Class<? extends Packet> clazz)
|
||||||
try {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
packets[id] = clazz.getDeclaredConstructor().newInstance();
|
packets[id] = clazz.getDeclaredConstructor().newInstance();
|
||||||
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException ex) {
|
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException ex)
|
||||||
|
{
|
||||||
$().severe("Could not register packet id " + Util.hex(id));
|
$().severe("Could not register packet id " + Util.hex(id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static
|
||||||
|
{
|
||||||
map(0, Packet0KeepAlive.class);
|
map(0, Packet0KeepAlive.class);
|
||||||
map(1, Packet1Login.class);
|
map(1, Packet1Login.class);
|
||||||
map(2, Packet2Handshake.class);
|
map(2, Packet2Handshake.class);
|
||||||
|
@ -3,7 +3,8 @@ package net.md_5.bungee.plugin;
|
|||||||
/**
|
/**
|
||||||
* An event which may be canceled and this be prevented from happening.
|
* An event which may be canceled and this be prevented from happening.
|
||||||
*/
|
*/
|
||||||
public interface Cancellable {
|
public interface Cancellable
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the canceled state of this event.
|
* Sets the canceled state of this event.
|
||||||
|
@ -9,7 +9,8 @@ import lombok.Data;
|
|||||||
* such as logging at the username has not yet been verified with Mojang.
|
* such as logging at the username has not yet been verified with Mojang.
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class HandshakeEvent implements Cancellable {
|
public class HandshakeEvent implements Cancellable
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Canceled state.
|
* Canceled state.
|
||||||
|
@ -3,15 +3,18 @@ package net.md_5.bungee.plugin;
|
|||||||
/**
|
/**
|
||||||
* Exception thrown when a plugin could not be loaded for any reason.
|
* Exception thrown when a plugin could not be loaded for any reason.
|
||||||
*/
|
*/
|
||||||
public class InvalidPluginException extends RuntimeException {
|
public class InvalidPluginException extends RuntimeException
|
||||||
|
{
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
public InvalidPluginException(String message, Throwable cause) {
|
public InvalidPluginException(String message, Throwable cause)
|
||||||
|
{
|
||||||
super(message, cause);
|
super(message, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InvalidPluginException(String message) {
|
public InvalidPluginException(String message)
|
||||||
|
{
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,8 @@ import net.md_5.bungee.command.Command;
|
|||||||
/**
|
/**
|
||||||
* Base class which all proxy plugins should extend.
|
* Base class which all proxy plugins should extend.
|
||||||
*/
|
*/
|
||||||
public abstract class JavaPlugin {
|
public abstract class JavaPlugin
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description file.
|
* Description file.
|
||||||
@ -16,26 +17,30 @@ public abstract class JavaPlugin {
|
|||||||
/**
|
/**
|
||||||
* Called on enable.
|
* Called on enable.
|
||||||
*/
|
*/
|
||||||
public void onEnable() {
|
public void onEnable()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called on disable.
|
* Called on disable.
|
||||||
*/
|
*/
|
||||||
public void onDisable() {
|
public void onDisable()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a user connects with their name and address. To keep things
|
* Called when a user connects with their name and address. To keep things
|
||||||
* simple this name has not been checked with minecraft.net.
|
* simple this name has not been checked with minecraft.net.
|
||||||
*/
|
*/
|
||||||
public void onHandshake(HandshakeEvent event) {
|
public void onHandshake(HandshakeEvent event)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a command for use with the proxy.
|
* Register a command for use with the proxy.
|
||||||
*/
|
*/
|
||||||
protected final void registerCommand(String label, Command command) {
|
protected final void registerCommand(String label, Command command)
|
||||||
|
{
|
||||||
BungeeCord.instance.commandMap.put(label, command);
|
BungeeCord.instance.commandMap.put(label, command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,8 @@ import static net.md_5.bungee.Logger.$;
|
|||||||
* Plugin manager to handle loading and saving other JavaPlugin's. This class is
|
* Plugin manager to handle loading and saving other JavaPlugin's. This class is
|
||||||
* itself a plugin for ease of use.
|
* itself a plugin for ease of use.
|
||||||
*/
|
*/
|
||||||
public class JavaPluginManager extends JavaPlugin {
|
public class JavaPluginManager extends JavaPlugin
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set of loaded plugins.
|
* Set of loaded plugins.
|
||||||
@ -28,23 +29,31 @@ public class JavaPluginManager extends JavaPlugin {
|
|||||||
* Load all plugins from the plugins folder. This method must only be called
|
* Load all plugins from the plugins folder. This method must only be called
|
||||||
* once per instance.
|
* once per instance.
|
||||||
*/
|
*/
|
||||||
public void loadPlugins() {
|
public void loadPlugins()
|
||||||
|
{
|
||||||
File dir = new File("plugins");
|
File dir = new File("plugins");
|
||||||
dir.mkdir();
|
dir.mkdir();
|
||||||
|
|
||||||
for (File file : dir.listFiles(new PatternFilenameFilter(".*\\.jar"))) {
|
for (File file : dir.listFiles(new PatternFilenameFilter(".*\\.jar")))
|
||||||
try {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
JarFile jar = new JarFile(file);
|
JarFile jar = new JarFile(file);
|
||||||
ZipEntry entry = jar.getEntry("plugin.yml");
|
ZipEntry entry = jar.getEntry("plugin.yml");
|
||||||
if (entry == null) {
|
if (entry == null)
|
||||||
|
{
|
||||||
throw new InvalidPluginException("Jar does not contain a plugin.yml");
|
throw new InvalidPluginException("Jar does not contain a plugin.yml");
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginDescription description;
|
PluginDescription description;
|
||||||
try (InputStream is = jar.getInputStream(entry)) {
|
try (InputStream is = jar.getInputStream(entry))
|
||||||
|
{
|
||||||
description = PluginDescription.load(is);
|
description = PluginDescription.load(is);
|
||||||
}
|
}
|
||||||
URLClassLoader classloader = new URLClassLoader(new URL[]{file.toURI().toURL()}, getClass().getClassLoader());
|
URLClassLoader classloader = new URLClassLoader(new URL[]
|
||||||
|
{
|
||||||
|
file.toURI().toURL()
|
||||||
|
}, getClass().getClassLoader());
|
||||||
Class<?> clazz = Class.forName(description.getMain(), true, classloader);
|
Class<?> clazz = Class.forName(description.getMain(), true, classloader);
|
||||||
Class<? extends JavaPlugin> subClazz = clazz.asSubclass(JavaPlugin.class);
|
Class<? extends JavaPlugin> subClazz = clazz.asSubclass(JavaPlugin.class);
|
||||||
JavaPlugin plugin = subClazz.getDeclaredConstructor().newInstance();
|
JavaPlugin plugin = subClazz.getDeclaredConstructor().newInstance();
|
||||||
@ -54,7 +63,8 @@ public class JavaPluginManager extends JavaPlugin {
|
|||||||
plugins.add(plugin);
|
plugins.add(plugin);
|
||||||
|
|
||||||
$().info("Loaded plugin: " + plugin.description.getName());
|
$().info("Loaded plugin: " + plugin.description.getName());
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
$().severe("Could not load plugin: " + file);
|
$().severe("Could not load plugin: " + file);
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -62,15 +72,19 @@ public class JavaPluginManager extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable()
|
||||||
for (JavaPlugin p : plugins) {
|
{
|
||||||
|
for (JavaPlugin p : plugins)
|
||||||
|
{
|
||||||
p.onDisable();
|
p.onDisable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onHandshake(HandshakeEvent event) {
|
public void onHandshake(HandshakeEvent event)
|
||||||
for (JavaPlugin p : plugins) {
|
{
|
||||||
|
for (JavaPlugin p : plugins)
|
||||||
|
{
|
||||||
p.onHandshake(event);
|
p.onHandshake(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,28 +10,36 @@ import org.yaml.snakeyaml.Yaml;
|
|||||||
* it.
|
* it.
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class PluginDescription {
|
public class PluginDescription
|
||||||
|
{
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
private String main;
|
private String main;
|
||||||
private String version;
|
private String version;
|
||||||
private String author;
|
private String author;
|
||||||
|
|
||||||
private PluginDescription() {
|
private PluginDescription()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PluginDescription load(InputStream is) {
|
public static PluginDescription load(InputStream is)
|
||||||
|
{
|
||||||
PluginDescription ret = new Yaml().loadAs(is, PluginDescription.class);
|
PluginDescription ret = new Yaml().loadAs(is, PluginDescription.class);
|
||||||
if (ret == null) {
|
if (ret == null)
|
||||||
|
{
|
||||||
throw new InvalidPluginException("Could not load plugin description file.");
|
throw new InvalidPluginException("Could not load plugin description file.");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Field f : PluginDescription.class.getDeclaredFields()) {
|
for (Field f : PluginDescription.class.getDeclaredFields())
|
||||||
try {
|
{
|
||||||
if (f.get(ret) == null) {
|
try
|
||||||
|
{
|
||||||
|
if (f.get(ret) == null)
|
||||||
|
{
|
||||||
throw new InvalidPluginException(f.getName() + " is not set properly in plugin description");
|
throw new InvalidPluginException(f.getName() + " is not set properly in plugin description");
|
||||||
}
|
}
|
||||||
} catch (IllegalArgumentException | IllegalAccessException ex) {
|
} catch (IllegalArgumentException | IllegalAccessException ex)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,21 +4,26 @@ import java.io.DataInputStream;
|
|||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public abstract class Packet {
|
public abstract class Packet
|
||||||
|
{
|
||||||
|
|
||||||
public boolean lowPriority = false;
|
public boolean lowPriority = false;
|
||||||
|
|
||||||
public static void a(DataOutputStream dataoutputstream, byte[] abyte) throws IOException {
|
public static void a(DataOutputStream dataoutputstream, byte[] abyte) throws IOException
|
||||||
|
{
|
||||||
dataoutputstream.writeShort(abyte.length);
|
dataoutputstream.writeShort(abyte.length);
|
||||||
dataoutputstream.write(abyte);
|
dataoutputstream.write(abyte);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] b(DataInputStream datainputstream) throws IOException {
|
public static byte[] b(DataInputStream datainputstream) throws IOException
|
||||||
|
{
|
||||||
short short1 = datainputstream.readShort();
|
short short1 = datainputstream.readShort();
|
||||||
|
|
||||||
if (short1 < 0) {
|
if (short1 < 0)
|
||||||
|
{
|
||||||
throw new IOException("Key was smaller than nothing! Weird key!");
|
throw new IOException("Key was smaller than nothing! Weird key!");
|
||||||
} else {
|
} else
|
||||||
|
{
|
||||||
byte[] abyte = new byte[short1];
|
byte[] abyte = new byte[short1];
|
||||||
|
|
||||||
datainputstream.read(abyte);
|
datainputstream.read(abyte);
|
||||||
@ -26,15 +31,19 @@ public abstract class Packet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String a(DataInputStream datainputstream, int i) throws IOException {
|
public static String a(DataInputStream datainputstream, int i) throws IOException
|
||||||
|
{
|
||||||
short short1 = datainputstream.readShort();
|
short short1 = datainputstream.readShort();
|
||||||
|
|
||||||
if (short1 < 0) {
|
if (short1 < 0)
|
||||||
|
{
|
||||||
throw new IOException("Received string length is less than zero! Weird string!");
|
throw new IOException("Received string length is less than zero! Weird string!");
|
||||||
} else {
|
} else
|
||||||
|
{
|
||||||
StringBuilder stringbuilder = new StringBuilder();
|
StringBuilder stringbuilder = new StringBuilder();
|
||||||
|
|
||||||
for (int j = 0; j < short1; ++j) {
|
for (int j = 0; j < short1; ++j)
|
||||||
|
{
|
||||||
stringbuilder.append(datainputstream.readChar());
|
stringbuilder.append(datainputstream.readChar());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,11 +59,13 @@ public abstract class Packet {
|
|||||||
|
|
||||||
public abstract int a();
|
public abstract int a();
|
||||||
|
|
||||||
public static ItemStack c(DataInputStream datainputstream) throws IOException {
|
public static ItemStack c(DataInputStream datainputstream) throws IOException
|
||||||
|
{
|
||||||
ItemStack itemstack = null;
|
ItemStack itemstack = null;
|
||||||
short short1 = datainputstream.readShort();
|
short short1 = datainputstream.readShort();
|
||||||
|
|
||||||
if (short1 >= 0) {
|
if (short1 >= 0)
|
||||||
|
{
|
||||||
byte b0 = datainputstream.readByte();
|
byte b0 = datainputstream.readByte();
|
||||||
short short2 = datainputstream.readShort();
|
short short2 = datainputstream.readShort();
|
||||||
|
|
||||||
@ -65,12 +76,15 @@ public abstract class Packet {
|
|||||||
return itemstack;
|
return itemstack;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NBTTagCompound d(DataInputStream datainputstream) throws IOException {
|
public static NBTTagCompound d(DataInputStream datainputstream) throws IOException
|
||||||
|
{
|
||||||
short short1 = datainputstream.readShort();
|
short short1 = datainputstream.readShort();
|
||||||
|
|
||||||
if (short1 < 0) {
|
if (short1 < 0)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else
|
||||||
|
{
|
||||||
byte[] abyte = new byte[short1];
|
byte[] abyte = new byte[short1];
|
||||||
|
|
||||||
datainputstream.readFully(abyte);
|
datainputstream.readFully(abyte);
|
||||||
|
@ -4,10 +4,12 @@ import java.io.DataInputStream;
|
|||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class Packet51MapChunk extends Packet {
|
public class Packet51MapChunk extends Packet
|
||||||
|
{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void a(DataInputStream datainputstream) throws IOException {
|
public void a(DataInputStream datainputstream) throws IOException
|
||||||
|
{
|
||||||
datainputstream.readInt();
|
datainputstream.readInt();
|
||||||
datainputstream.readInt();
|
datainputstream.readInt();
|
||||||
datainputstream.readBoolean();
|
datainputstream.readBoolean();
|
||||||
@ -19,15 +21,18 @@ public class Packet51MapChunk extends Packet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void a(DataOutputStream dataoutputstream) throws IOException {
|
public void a(DataOutputStream dataoutputstream) throws IOException
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(NetHandler nethandler) {
|
public void handle(NetHandler nethandler)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int a() {
|
public int a()
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user