Initial commit.

This commit is contained in:
md_5
2012-10-05 11:01:31 +10:00
commit b876fb2e1b
23 changed files with 1495 additions and 0 deletions

View File

@@ -0,0 +1,108 @@
package net.md_5.bungee;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static net.md_5.bungee.Logger.$;
public class BungeeCord {
/**
* Current software instance.
*/
public static BungeeCord instance;
/**
* Current operation state.
*/
public volatile boolean isRunning;
/**
* Configuration.
*/
public final Configuration config = new Configuration();
/**
* Thread pool.
*/
public final ExecutorService threadPool = Executors.newCachedThreadPool();
/**
* locations.yml save thread.
*/
private final ReconnectSaveThread saveThread = new ReconnectSaveThread();
/**
* Server socket listener.
*/
private ListenThread listener;
/**
* Current version.
*/
private String version = (getClass().getPackage().getImplementationVersion() == null) ? "unknown" : getClass().getPackage().getImplementationVersion();
public static void main(String[] args) throws IOException {
System.out.println(Util.hex(15));
instance = new BungeeCord();
$().info("Enabled BungeeCord version " + instance.version);
instance.start();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while (instance.isRunning) {
String line = br.readLine();
if (line != null) {
if (line.equals("end")) {
instance.stop();
}
}
}
}
public void start() throws IOException {
config.load();
isRunning = true;
InetSocketAddress addr = Util.getAddr(config.bindHost);
listener = new ListenThread(addr);
listener.start();
saveThread.start();
$().info("Listening on " + addr);
}
public void stop() {
this.isRunning = false;
$().info("Closing listen thread");
try {
listener.socket.close();
listener.join();
} catch (InterruptedException | IOException ex) {
$().severe("Could not close listen thread");
}
$().info("Closing pending connections");
threadPool.shutdown();
$().info("Disconnecting " + "x" + " connections");
// TODO: Kick everyone
$().info("Saving reconnect locations");
saveThread.interrupt();
try {
saveThread.join();
} catch (InterruptedException ex) {
}
$().info("Thank you and goodbye");
}
public int getOnlinePlayers() {
return 123;
}
public void setSocketOptions(Socket socket) throws IOException {
socket.setSoTimeout(config.timeout);
socket.setTrafficClass(0x18);
socket.setTcpNoDelay(true);
}
}

View File

@@ -0,0 +1,236 @@
package net.md_5.bungee;
import com.google.common.collect.Maps;
import java.util.Map;
import java.util.regex.Pattern;
/**
* All supported color values for chat
*/
public enum ChatColor {
/**
* Represents black
*/
BLACK('0', 0x00),
/**
* Represents dark blue
*/
DARK_BLUE('1', 0x1),
/**
* Represents dark green
*/
DARK_GREEN('2', 0x2),
/**
* Represents dark blue (aqua)
*/
DARK_AQUA('3', 0x3),
/**
* Represents dark red
*/
DARK_RED('4', 0x4),
/**
* Represents dark purple
*/
DARK_PURPLE('5', 0x5),
/**
* Represents gold
*/
GOLD('6', 0x6),
/**
* Represents gray
*/
GRAY('7', 0x7),
/**
* Represents dark gray
*/
DARK_GRAY('8', 0x8),
/**
* Represents blue
*/
BLUE('9', 0x9),
/**
* Represents green
*/
GREEN('a', 0xA),
/**
* Represents aqua
*/
AQUA('b', 0xB),
/**
* Represents red
*/
RED('c', 0xC),
/**
* Represents light purple
*/
LIGHT_PURPLE('d', 0xD),
/**
* Represents yellow
*/
YELLOW('e', 0xE),
/**
* Represents white
*/
WHITE('f', 0xF),
/**
* Represents magical characters that change around randomly
*/
MAGIC('k', 0x10, true),
/**
* Makes the text bold.
*/
BOLD('l', 0x11, true),
/**
* Makes a line appear through the text.
*/
STRIKETHROUGH('m', 0x12, true),
/**
* Makes the text appear underlined.
*/
UNDERLINE('n', 0x13, true),
/**
* Makes the text italic.
*/
ITALIC('o', 0x14, true),
/**
* Resets all previous chat colors or formats.
*/
RESET('r', 0x15);
/**
* The special character which prefixes all chat colour codes. Use this if
* you need to dynamically convert colour codes from your custom format.
*/
public static final char COLOR_CHAR = '\u00A7';
private static final Pattern STRIP_COLOR_PATTERN = Pattern.compile("(?i)" + String.valueOf(COLOR_CHAR) + "[0-9A-FK-OR]");
private final int intCode;
private final char code;
private final boolean isFormat;
private final String toString;
private final static Map<Integer, ChatColor> BY_ID = Maps.newHashMap();
private final static Map<Character, ChatColor> BY_CHAR = Maps.newHashMap();
private ChatColor(char code, int intCode) {
this(code, intCode, false);
}
private ChatColor(char code, int intCode, boolean isFormat) {
this.code = code;
this.intCode = intCode;
this.isFormat = isFormat;
this.toString = new String(new char[]{COLOR_CHAR, code});
}
/**
* Gets the char value associated with this color
*
* @return A char value of this color code
*/
public char getChar() {
return code;
}
@Override
public String toString() {
return toString;
}
/**
* Checks if this code is a format code as opposed to a color code.
*/
public boolean isFormat() {
return isFormat;
}
/**
* Checks if this code is a color code as opposed to a format code.
*/
public boolean isColor() {
return !isFormat && this != RESET;
}
/**
* Gets the color represented by the specified color code
*
* @param code Code to check
* @return Associative {@link org.bukkit.ChatColor} with the given code, or
* null if it doesn't exist
*/
public static ChatColor getByChar(char code) {
return BY_CHAR.get(code);
}
/**
* Strips the given message of all color codes
*
* @param input String to strip of color
* @return A copy of the input string, without any coloring
*/
public static String stripColor(final String input) {
if (input == null) {
return null;
}
return STRIP_COLOR_PATTERN.matcher(input).replaceAll("");
}
/**
* Translates a string using an alternate color code character into a string
* that uses the internal ChatColor.COLOR_CODE color code character. The
* alternate color code character will only be replaced if it is immediately
* followed by 0-9, A-F, or a-f.
*
* @param altColorChar The alternate color code character to replace. Ex: &
* @param textToTranslate Text containing the alternate color code
* character.
* @return Text containing the ChatColor.COLOR_CODE color code character.
*/
public static String translateAlternateColorCodes(char altColorChar, String textToTranslate) {
char[] b = textToTranslate.toCharArray();
for (int i = 0; i < b.length - 1; i++) {
if (b[i] == altColorChar && "0123456789AaBbCcDdEeFfKkLlMmNnOoRr".indexOf(b[i + 1]) > -1) {
b[i] = ChatColor.COLOR_CHAR;
b[i + 1] = Character.toLowerCase(b[i + 1]);
}
}
return new String(b);
}
/**
* Gets the ChatColors used at the end of the given input string.
*
* @param input Input string to retrieve the colors from.
* @return Any remaining ChatColors to pass onto the next line.
*/
public static String getLastColors(String input) {
String result = "";
int length = input.length();
// Search backwards from the end as it is faster
for (int index = length - 1; index > -1; index--) {
char section = input.charAt(index);
if (section == COLOR_CHAR && index < length - 1) {
char c = input.charAt(index + 1);
ChatColor color = getByChar(c);
if (color != null) {
result = color.toString() + result;
// Once we find a color or reset we can stop searching
if (color.isColor() || color.equals(RESET)) {
break;
}
}
}
}
return result;
}
static {
for (ChatColor color : values()) {
BY_ID.put(color.intCode, color);
BY_CHAR.put(color.code, color);
}
}
}

View File

@@ -0,0 +1,201 @@
package net.md_5.bungee;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static net.md_5.bungee.Logger.$;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
public class Configuration {
/**
* Reconnect locations file.
*/
private transient File reconnect = new File("locations.yml");
/**
* Loaded reconnect locations.
*/
private transient Map<String, String> reconnectLocations;
/**
* Config file.
*/
private transient File file = new File("config.yml");
/**
* Yaml instance.
*/
private transient Yaml yaml;
/**
* Loaded config.
*/
private transient Map<String, Object> config;
/**
* Bind host.
*/
public String bindHost = "0.0.0.0:25577";
/**
* Server ping motd.
*/
public String motd = "BungeeCord Proxy Instance";
/**
* Name of default server.
*/
public String defaultServerName = "default";
/**
* Max players as displayed in list ping. Soft limit.
*/
public int maxPlayers = 1;
/**
* Socket timeout.
*/
public int timeout = 15000;
/**
* All servers.
*/
public Map<String, String> servers = new HashMap<String, String>() {
{
put(defaultServerName, "127.0.0.1");
put("pvp", "127.0.0.1:1337");
}
};
/**
* Forced servers.
*/
public Map<String, String> forcedServers = new HashMap<String, String>() {
{
put("pvp.md-5.net", "pvp");
}
};
/**
* Proxy admins.
*/
public List<String> admins = new ArrayList<String>() {
{
add("md_5");
}
};
/**
* Proxy moderators.
*/
public List<String> moderators = new ArrayList<String>() {
{
add("mbaxter");
}
};
public void load() {
try {
file.createNewFile();
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
yaml = new Yaml(options);
try (InputStream is = new FileInputStream(file)) {
config = (Map) yaml.load(is);
}
if (config == null) {
config = new LinkedHashMap<>();
}
$().info("-------------- Loading configuration ----------------");
for (Field field : getClass().getDeclaredFields()) {
if (!Modifier.isTransient(field.getModifiers())) {
String name = Util.normalize(field.getName());
try {
Object def = field.get(this);
Object value = get(name, def);
field.set(this, value);
$().info(name + ": " + value);
} catch (IllegalAccessException ex) {
$().severe("Could not get config node: " + name);
}
}
}
$().info("-----------------------------------------------------");
if (servers.get(defaultServerName) == null) {
throw new IllegalArgumentException("Server '" + defaultServerName + "' not defined");
}
for (String server : forcedServers.values()) {
if (!servers.containsKey(server)) {
throw new IllegalArgumentException("Forced server " + server + " is not defined in servers");
}
}
reconnect.createNewFile();
try (FileInputStream recon = new FileInputStream(reconnect)) {
reconnectLocations = (Map) yaml.load(recon);
}
if (reconnectLocations == null) {
reconnectLocations = new LinkedHashMap<>();
}
} catch (IOException ex) {
$().severe("Could not load config!");
ex.printStackTrace();
}
}
private <T> T get(String path, T def) {
if (!config.containsKey(path)) {
config.put(path, def);
save(file, config);
}
return (T) config.get(path);
}
private void save(File fileToSave, Map toSave) {
try {
try (FileWriter wr = new FileWriter(fileToSave)) {
yaml.dump(toSave, wr);
}
} catch (IOException ex) {
$().severe("Could not save config file " + fileToSave);
ex.printStackTrace();
}
}
public InetSocketAddress getHostFor(String user, InetSocketAddress requestedHost) {
String entry = user + ";" + Util.getAddr(requestedHost);
String host = requestedHost.getHostString();
String hostLine;
if (forcedServers.containsKey(host)) {
hostLine = servers.get(forcedServers.get(host));
} else {
hostLine = reconnectLocations.get(entry);
}
if (hostLine == null) {
hostLine = servers.get(defaultServerName);
}
return Util.getAddr(hostLine);
}
public InetSocketAddress getServer(String name) {
String hostline = servers.get(name);
if (hostline != null) {
return Util.getAddr(hostline);
} else {
return null;
}
}
public void saveHosts() {
save(reconnect, reconnectLocations);
$().info("Saved reconnect locations to " + reconnect);
}
}

View File

@@ -0,0 +1,61 @@
package net.md_5.bungee;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import net.md_5.bungee.packet.Packet2Handshake;
import net.md_5.bungee.packet.PacketFFKick;
import net.md_5.bungee.packet.PacketInputStream;
public class InitialHandler implements Runnable {
private final Socket socket;
private final PacketInputStream in;
private final OutputStream out;
public InitialHandler(Socket socket) throws IOException {
this.socket = socket;
in = new PacketInputStream(socket.getInputStream());
out = socket.getOutputStream();
}
@Override
public void run() {
try {
byte[] packet = in.readPacket();
int id = Util.getId(packet);
switch (id) {
case 0x02:
Packet2Handshake handshake = new Packet2Handshake(packet);
break;
case 0xFE:
throw new KickException(BungeeCord.instance.config.motd + ChatColor.COLOR_CHAR + BungeeCord.instance.getOnlinePlayers() + ChatColor.COLOR_CHAR + BungeeCord.instance.config.maxPlayers);
default:
throw new IllegalArgumentException("Wasn't ready for packet id " + Util.hex(id));
}
} catch (KickException ex) {
kick(ex.getMessage());
} catch (Exception ex) {
kick("[Proxy Error] " + Util.exception(ex));
}
}
private void kick(String message) {
try {
out.write(new PacketFFKick(message).getPacket());
} catch (IOException ioe) {
} finally {
try {
socket.close();
} catch (IOException ioe2) {
}
}
}
private class KickException extends RuntimeException {
public KickException(String message) {
super(message);
}
}
}

View File

@@ -0,0 +1,35 @@
package net.md_5.bungee;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import static net.md_5.bungee.Logger.$;
public class ListenThread extends Thread {
public final ServerSocket socket;
public ListenThread(InetSocketAddress addr) throws IOException {
super("Listen Thread");
socket = new ServerSocket();
socket.bind(addr);
}
@Override
public void run() {
while (BungeeCord.instance.isRunning) {
try {
Socket client = socket.accept();
BungeeCord.instance.setSocketOptions(client);
$().info(client.getInetAddress() + " has connected");
InitialHandler handler = new InitialHandler(client);
BungeeCord.instance.threadPool.submit(handler);
} catch (SocketException ex) {
} catch (IOException ex) {
ex.printStackTrace(); // TODO
}
}
}
}

View File

@@ -0,0 +1,20 @@
package net.md_5.bungee;
public class ReconnectSaveThread extends Thread {
public ReconnectSaveThread() {
super("Location Save Thread");
setPriority(Thread.MIN_PRIORITY);
}
@Override
public void run() {
while (BungeeCord.instance.isRunning) {
try {
Thread.sleep(5 * 1000 * 60); // 5 minutes
} catch (InterruptedException ex) {
}
BungeeCord.instance.config.saveHosts();
}
}
}

View File

@@ -0,0 +1,70 @@
package net.md_5.bungee;
import java.net.InetSocketAddress;
public class Util {
private static final int DEFAULT_PORT = 25565;
/**
* Basic method to transform human readable addresses into usable address
* objects.
*
* @param hostline in the format of 'host:port'
* @return the constructed hostname + port.
*/
public static InetSocketAddress getAddr(String hostline) {
String[] split = hostline.split(":");
if (split.length < 2) {
throw new IllegalArgumentException("Invalid split format");
}
int port = DEFAULT_PORT;
if (split.length > 1) {
port = Integer.parseInt(split[1]);
}
return new InetSocketAddress(split[0], port);
}
/**
* Turns a InetSocketAddress into a string that can be reconstructed later.
*
* @param address the address to serialize
* @return
*/
public static String getAddr(InetSocketAddress address) {
return address.getAddress().getHostAddress() + ((address.getPort() != DEFAULT_PORT) ? ":" + address.getPort() : "");
}
/**
* Get the packet id of specified byte array.
*/
public static int getId(byte[] b) {
return b[0] & 0xFF;
}
/**
* Normalizes a config path by prefix upper case letters with '_' and
* turning them to lowercase.
*
* @param s the string to normalize
* @return the normalized path
*/
public static String normalize(String s) {
StringBuilder result = new StringBuilder();
for (char c : s.toCharArray()) {
if (Character.isUpperCase(c)) {
result.append("_");
}
result.append(Character.toLowerCase(c));
}
return result.toString();
}
public static String hex(int i) {
return String.format("0x%02X", i);
}
public static String exception(Throwable t) {
return t.getClass().getSimpleName() + " : " + t.getMessage() + " @ " + t.getStackTrace()[0].getFileName() + ":" + t.getStackTrace()[0].getLineNumber();
}
}

View File

@@ -0,0 +1,88 @@
package net.md_5.bungee.packet;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import java.io.DataInput;
import java.io.DataOutput;
import lombok.Delegate;
import net.md_5.bungee.Util;
public abstract class DefinedPacket implements DataInput, DataOutput {
private interface Overriden {
void readUTF();
void writeUTF(String s);
}
@Delegate(excludes = Overriden.class)
private ByteArrayDataInput in;
@Delegate(excludes = Overriden.class)
private ByteArrayDataOutput out;
/**
* Packet id.
*/
public final int id;
/**
* Already constructed packet.
*/
private byte[] packet;
public DefinedPacket(int id, byte[] buf) {
in = ByteStreams.newDataInput(buf);
if (readUnsignedByte() != id) {
throw new IllegalArgumentException("Wasn't expecting packet id " + Util.hex(id));
}
this.id = id;
packet = buf;
}
public DefinedPacket(int id) {
out = ByteStreams.newDataOutput();
this.id = id;
writeByte(id);
packet = null;
}
public byte[] getPacket() {
return packet == null ? out.toByteArray() : packet;
}
@Override
public void writeUTF(String s) {
writeShort(s.length());
writeChars(s);
}
@Override
public String readUTF() {
short len = readShort();
char[] chars = new char[len];
for (int i = 0; i < len; i++) {
chars[i] = this.readChar();
}
return new String(chars);
}
public void writeArray(byte[] b) {
writeShort(b.length);
write(b);
}
public byte[] readArray() {
short len = readShort();
byte[] ret = new byte[len];
readFully(ret);
return ret;
}
@Override
public abstract boolean equals(Object obj);
@Override
public abstract int hashCode();
@Override
public abstract String toString();
}

View File

@@ -0,0 +1,21 @@
package net.md_5.bungee.packet;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ToString
@EqualsAndHashCode(callSuper = false)
public class Packet10HeldItem extends DefinedPacket {
public short slot;
public Packet10HeldItem(short slot) {
super(0x10);
writeShort(slot);
}
public Packet10HeldItem(byte[] buf) {
super(0x10, buf);
this.slot = readShort();
}
}

View File

@@ -0,0 +1,30 @@
package net.md_5.bungee.packet;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ToString
@EqualsAndHashCode(callSuper = false)
public class Packet2Handshake extends DefinedPacket {
public byte procolVersion;
public String username;
public String host;
public int port;
public Packet2Handshake(byte protocolVersion, String username, String host, int port) {
super(0x02);
writeByte(protocolVersion);
writeUTF(username);
writeUTF(host);
writeInt(port);
}
public Packet2Handshake(byte[] buf) {
super(0x02, buf);
this.procolVersion = readByte();
this.username = readUTF();
this.host = readUTF();
this.port = readInt();
}
}

View File

@@ -0,0 +1,21 @@
package net.md_5.bungee.packet;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ToString
@EqualsAndHashCode(callSuper = false)
public class Packet3Chat extends DefinedPacket {
public String message;
public Packet3Chat(String message) {
super(0x03);
writeUTF(message);
}
public Packet3Chat(byte[] buf) {
super(0x03, buf);
this.message = readUTF();
}
}

View File

@@ -0,0 +1,21 @@
package net.md_5.bungee.packet;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ToString
@EqualsAndHashCode(callSuper = false)
public class Packet46GameState extends DefinedPacket {
/**
* Update game state. When sent with a state of 2, rain will cease.
*
* @param state the new game state
* @param mode the new game mode. Used when state == 3.
*/
public Packet46GameState(byte state, byte mode) {
super(0x46);
writeByte(state);
writeByte(mode);
}
}

View File

@@ -0,0 +1,33 @@
package net.md_5.bungee.packet;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ToString
@EqualsAndHashCode(callSuper = false)
public class Packet9Respawn extends DefinedPacket {
public int dimension;
public byte difficulty;
public byte gameMode;
public short worldHeight;
public String levelType;
public Packet9Respawn(int dimension, byte difficulty, byte gameMode, short worldHeight, String levelType) {
super(0x09);
writeInt(dimension);
writeByte(difficulty);
writeByte(gameMode);
writeShort(worldHeight);
writeUTF(levelType);
}
public Packet9Respawn(byte[] buf) {
super(0x09, buf);
this.dimension = readInt();
this.difficulty = readByte();
this.gameMode = readByte();
this.worldHeight = readShort();
this.levelType = readUTF();
}
}

View File

@@ -0,0 +1,26 @@
package net.md_5.bungee.packet;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ToString
@EqualsAndHashCode(callSuper = false)
public class PacketFAPluginMessage extends DefinedPacket {
public String tag;
public byte[] data;
public PacketFAPluginMessage(String tag, byte[] data) {
super(0xFA);
writeUTF(tag);
writeArray(data);
this.tag = tag;
this.data = data;
}
public PacketFAPluginMessage(byte[] buf) {
super(0xFA, buf);
this.tag = readUTF();
this.data = readArray();
}
}

View File

@@ -0,0 +1,24 @@
package net.md_5.bungee.packet;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ToString
@EqualsAndHashCode(callSuper = false)
public class PacketFCEncryptionResponse extends DefinedPacket {
public byte[] sharedSecret;
public byte[] verifyToken;
public PacketFCEncryptionResponse() {
super(0xFC);
writeArray(new byte[0]);
writeArray(new byte[0]);
}
public PacketFCEncryptionResponse(byte[] buf) {
super(0xFC, buf);
this.sharedSecret = readArray();
this.verifyToken = readArray();
}
}

View File

@@ -0,0 +1,23 @@
package net.md_5.bungee.packet;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ToString
@EqualsAndHashCode(callSuper = false)
public class PacketFDEncryptionRequest extends DefinedPacket {
public String serverId;
public byte[] publicKey;
public byte[] verifyToken;
public PacketFDEncryptionRequest(String serverId, byte[] publicKey, byte[] verifyToken) {
super(0xFD);
writeUTF(serverId);
writeArray(publicKey);
writeArray(verifyToken);
this.serverId = serverId;
this.publicKey = publicKey;
this.verifyToken = verifyToken;
}
}

View File

@@ -0,0 +1,21 @@
package net.md_5.bungee.packet;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ToString
@EqualsAndHashCode(callSuper = false)
public class PacketFFKick extends DefinedPacket {
public String message;
public PacketFFKick(String message) {
super(0xFF);
writeUTF(message);
}
public PacketFFKick(byte[] buf) {
super(0xFF, buf);
this.message = readUTF();
}
}

View File

@@ -0,0 +1,48 @@
package net.md_5.bungee.packet;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import net.md_5.bungee.Util;
import net.minecraft.server.Packet;
public class PacketInputStream {
private final DataInputStream dataInput;
private final TrackingInputStream tracker;
public PacketInputStream(InputStream in) {
tracker = new TrackingInputStream(in);
dataInput = new DataInputStream(tracker);
}
public byte[] readPacket() throws IOException {
tracker.out.reset();
int id = tracker.read();
Packet codec = VanillaPackets.packets[id];
if (codec == null) {
throw new RuntimeException("No Packet id: " + Util.hex(id));
}
codec.a(dataInput);
return tracker.out.toByteArray();
}
private class TrackingInputStream extends InputStream {
private final ByteArrayOutputStream out = new ByteArrayOutputStream();
private final InputStream wrapped;
public TrackingInputStream(InputStream wrapped) {
this.wrapped = wrapped;
}
@Override
public int read() throws IOException {
int ret = wrapped.read();
out.write(ret);
return ret;
}
}
}

View File

@@ -0,0 +1,172 @@
package net.md_5.bungee.packet;
import java.lang.reflect.InvocationTargetException;
import static net.md_5.bungee.Logger.$;
import net.md_5.bungee.Util;
import net.minecraft.server.Packet;
import net.minecraft.server.Packet0KeepAlive;
import net.minecraft.server.Packet100OpenWindow;
import net.minecraft.server.Packet101CloseWindow;
import net.minecraft.server.Packet102WindowClick;
import net.minecraft.server.Packet103SetSlot;
import net.minecraft.server.Packet104WindowItems;
import net.minecraft.server.Packet105CraftProgressBar;
import net.minecraft.server.Packet106Transaction;
import net.minecraft.server.Packet107SetCreativeSlot;
import net.minecraft.server.Packet108ButtonClick;
import net.minecraft.server.Packet10Flying;
import net.minecraft.server.Packet11PlayerPosition;
import net.minecraft.server.Packet12PlayerLook;
import net.minecraft.server.Packet130UpdateSign;
import net.minecraft.server.Packet131ItemData;
import net.minecraft.server.Packet132TileEntityData;
import net.minecraft.server.Packet13PlayerLookMove;
import net.minecraft.server.Packet14BlockDig;
import net.minecraft.server.Packet15Place;
import net.minecraft.server.Packet16BlockItemSwitch;
import net.minecraft.server.Packet17EntityLocationAction;
import net.minecraft.server.Packet18ArmAnimation;
import net.minecraft.server.Packet19EntityAction;
import net.minecraft.server.Packet1Login;
import net.minecraft.server.Packet200Statistic;
import net.minecraft.server.Packet201PlayerInfo;
import net.minecraft.server.Packet202Abilities;
import net.minecraft.server.Packet203TabComplete;
import net.minecraft.server.Packet204LocaleAndViewDistance;
import net.minecraft.server.Packet205ClientCommand;
import net.minecraft.server.Packet20NamedEntitySpawn;
import net.minecraft.server.Packet21PickupSpawn;
import net.minecraft.server.Packet22Collect;
import net.minecraft.server.Packet23VehicleSpawn;
import net.minecraft.server.Packet24MobSpawn;
import net.minecraft.server.Packet250CustomPayload;
import net.minecraft.server.Packet252KeyResponse;
import net.minecraft.server.Packet253KeyRequest;
import net.minecraft.server.Packet254GetInfo;
import net.minecraft.server.Packet255KickDisconnect;
import net.minecraft.server.Packet25EntityPainting;
import net.minecraft.server.Packet26AddExpOrb;
import net.minecraft.server.Packet28EntityVelocity;
import net.minecraft.server.Packet29DestroyEntity;
import net.minecraft.server.Packet2Handshake;
import net.minecraft.server.Packet30Entity;
import net.minecraft.server.Packet31RelEntityMove;
import net.minecraft.server.Packet32EntityLook;
import net.minecraft.server.Packet33RelEntityMoveLook;
import net.minecraft.server.Packet34EntityTeleport;
import net.minecraft.server.Packet35EntityHeadRotation;
import net.minecraft.server.Packet38EntityStatus;
import net.minecraft.server.Packet39AttachEntity;
import net.minecraft.server.Packet3Chat;
import net.minecraft.server.Packet40EntityMetadata;
import net.minecraft.server.Packet41MobEffect;
import net.minecraft.server.Packet42RemoveMobEffect;
import net.minecraft.server.Packet43SetExperience;
import net.minecraft.server.Packet4UpdateTime;
import net.minecraft.server.Packet51MapChunk;
import net.minecraft.server.Packet52MultiBlockChange;
import net.minecraft.server.Packet53BlockChange;
import net.minecraft.server.Packet54PlayNoteBlock;
import net.minecraft.server.Packet55BlockBreakAnimation;
import net.minecraft.server.Packet56MapChunkBulk;
import net.minecraft.server.Packet5EntityEquipment;
import net.minecraft.server.Packet60Explosion;
import net.minecraft.server.Packet61WorldEvent;
import net.minecraft.server.Packet62NamedSoundEffect;
import net.minecraft.server.Packet6SpawnPosition;
import net.minecraft.server.Packet70Bed;
import net.minecraft.server.Packet71Weather;
import net.minecraft.server.Packet7UseEntity;
import net.minecraft.server.Packet8UpdateHealth;
import net.minecraft.server.Packet9Respawn;
public class VanillaPackets {
public static Packet[] packets = new Packet[256];
private static void map(int id, Class clazz) {
try {
packets[id] = (Packet) clazz.getDeclaredConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException ex) {
$().severe("Could not register packet id " + Util.hex(id));
}
}
static {
map(0, Packet0KeepAlive.class);
map(1, Packet1Login.class);
map(2, Packet2Handshake.class);
map(3, Packet3Chat.class);
map(4, Packet4UpdateTime.class);
map(5, Packet5EntityEquipment.class);
map(6, Packet6SpawnPosition.class);
map(7, Packet7UseEntity.class);
map(8, Packet8UpdateHealth.class);
map(9, Packet9Respawn.class);
map(10, Packet10Flying.class);
map(11, Packet11PlayerPosition.class);
map(12, Packet12PlayerLook.class);
map(13, Packet13PlayerLookMove.class);
map(14, Packet14BlockDig.class);
map(15, Packet15Place.class);
map(16, Packet16BlockItemSwitch.class);
map(17, Packet17EntityLocationAction.class);
map(18, Packet18ArmAnimation.class);
map(19, Packet19EntityAction.class);
map(20, Packet20NamedEntitySpawn.class);
map(21, Packet21PickupSpawn.class);
map(22, Packet22Collect.class);
map(23, Packet23VehicleSpawn.class);
map(24, Packet24MobSpawn.class);
map(25, Packet25EntityPainting.class);
map(26, Packet26AddExpOrb.class);
map(28, Packet28EntityVelocity.class);
map(29, Packet29DestroyEntity.class);
map(30, Packet30Entity.class);
map(31, Packet31RelEntityMove.class);
map(32, Packet32EntityLook.class);
map(33, Packet33RelEntityMoveLook.class);
map(34, Packet34EntityTeleport.class);
map(35, Packet35EntityHeadRotation.class);
map(38, Packet38EntityStatus.class);
map(39, Packet39AttachEntity.class);
map(40, Packet40EntityMetadata.class);
map(41, Packet41MobEffect.class);
map(42, Packet42RemoveMobEffect.class);
map(43, Packet43SetExperience.class);
map(51, Packet51MapChunk.class);
map(52, Packet52MultiBlockChange.class);
map(53, Packet53BlockChange.class);
map(54, Packet54PlayNoteBlock.class);
map(55, Packet55BlockBreakAnimation.class);
map(56, Packet56MapChunkBulk.class);
map(60, Packet60Explosion.class);
map(61, Packet61WorldEvent.class);
map(62, Packet62NamedSoundEffect.class);
map(70, Packet70Bed.class);
map(71, Packet71Weather.class);
map(100, Packet100OpenWindow.class);
map(101, Packet101CloseWindow.class);
map(102, Packet102WindowClick.class);
map(103, Packet103SetSlot.class);
map(104, Packet104WindowItems.class);
map(105, Packet105CraftProgressBar.class);
map(106, Packet106Transaction.class);
map(107, Packet107SetCreativeSlot.class);
map(108, Packet108ButtonClick.class);
map(130, Packet130UpdateSign.class);
map(131, Packet131ItemData.class);
map(132, Packet132TileEntityData.class);
map(200, Packet200Statistic.class);
map(201, Packet201PlayerInfo.class);
map(202, Packet202Abilities.class);
map(203, Packet203TabComplete.class);
map(204, Packet204LocaleAndViewDistance.class);
map(205, Packet205ClientCommand.class);
map(250, Packet250CustomPayload.class);
map(252, Packet252KeyResponse.class);
map(253, Packet253KeyRequest.class);
map(254, Packet254GetInfo.class);
map(255, Packet255KickDisconnect.class);
}
}