Initial commit.
This commit is contained in:
commit
b876fb2e1b
38
.gitignore
vendored
Normal file
38
.gitignore
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
# Eclipse stuff
|
||||
/.classpath
|
||||
/.project
|
||||
/.settings
|
||||
|
||||
# netbeans
|
||||
/nbproject
|
||||
/nbactions.xml
|
||||
/nb-configuration.xml
|
||||
|
||||
# we use maven!
|
||||
/build.xml
|
||||
|
||||
# maven
|
||||
/target
|
||||
/dependency-reduced-pom.xml
|
||||
|
||||
# vim
|
||||
.*.sw[a-p]
|
||||
|
||||
# various other potential build files
|
||||
/build
|
||||
/bin
|
||||
/dist
|
||||
/manifest.mf
|
||||
|
||||
# Mac filesystem dust
|
||||
/.DS_Store
|
||||
|
||||
# intellij
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# other files
|
||||
*log*
|
||||
*.yml
|
26
LICENSE
Normal file
26
LICENSE
Normal file
@ -0,0 +1,26 @@
|
||||
Copyright (c) 2012, md_5. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
13
README.md
Normal file
13
README.md
Normal file
@ -0,0 +1,13 @@
|
||||
BungeeCord
|
||||
======
|
||||
|
||||
The most reliable Minecraft server portal suite.
|
||||
|
||||
Coding guidelines
|
||||
-----------
|
||||
|
||||
Its not fun to always have to stick to a set of rules, but here are are few to make sure everyone gets the best experience.
|
||||
* Have verbose commit messages, this makes it much easier to revert commits if the need arises.
|
||||
* Rebase your commits onto the tracked branch. No merges please.
|
||||
* Use for spaces, NO tabs.
|
||||
* Use lombok wherever possible.
|
159
pom.xml
Normal file
159
pom.xml
Normal file
@ -0,0 +1,159 @@
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord</name>
|
||||
<url>https://github.com/Shadowraze/BungeeCord</url>
|
||||
<inceptionYear>2012</inceptionYear>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The BSD 3-Clause License</name>
|
||||
<url>http://opensource.org/licenses/BSD-3-Clause</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:git@github.com:Shadowraze/BungeeCord.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:Shadowraze/BungeeCord.git</developerConnection>
|
||||
<url>git@github.com:Shadowraze/BungeeCord.git</url>
|
||||
</scm>
|
||||
<issueManagement>
|
||||
<system>GitHub</system>
|
||||
<url>https://github.com/Shadowraze/BungeeCord/issues</url>
|
||||
</issueManagement>
|
||||
<ciManagement>
|
||||
<system>jenkins</system>
|
||||
<url>http://ci.md-5.net/job/BungeeCord</url>
|
||||
</ciManagement>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<build.number>unknown</build.number>
|
||||
<main.class>net.md_5.bungee.BungeeCord</main.class>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>13.0.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
<version>1.47</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>minecraft-server</artifactId>
|
||||
<version>1.3.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>1.11</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>0.11.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>repobo-snap</id>
|
||||
<url>http://repo.bukkit.org/content/groups/public</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>bukkit-plugins</id>
|
||||
<url>http://repo.bukkit.org/content/groups/public</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<build>
|
||||
<finalName>${project.name}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.lukegb.mojo</groupId>
|
||||
<artifactId>gitdescribe-maven-plugin</artifactId>
|
||||
<version>1.3</version>
|
||||
<configuration>
|
||||
<outputPrefix>git-${project.name}-${project.version}-</outputPrefix>
|
||||
<outputPostfix>-${build.number}</outputPostfix>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>gitdescribe</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.5.1</version>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<Main-Class>${main.class}</Main-Class>
|
||||
<Implementation-Version>${describe}</Implementation-Version>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<filters>
|
||||
<filter>
|
||||
<artifact>*:*</artifact>
|
||||
<excludes>
|
||||
<exclude>META-INF/*.SF</exclude>
|
||||
<exclude>META-INF/*.DSA</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
<filter>
|
||||
<artifact>org.bukkit:minecraft-server</artifact>
|
||||
<excludes>
|
||||
<exclude>org/bouncycastle/**</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
</filters>
|
||||
<minimizeJar>true</minimizeJar>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
108
src/main/java/net/md_5/bungee/BungeeCord.java
Normal file
108
src/main/java/net/md_5/bungee/BungeeCord.java
Normal 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);
|
||||
}
|
||||
}
|
236
src/main/java/net/md_5/bungee/ChatColor.java
Normal file
236
src/main/java/net/md_5/bungee/ChatColor.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
201
src/main/java/net/md_5/bungee/Configuration.java
Normal file
201
src/main/java/net/md_5/bungee/Configuration.java
Normal 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);
|
||||
}
|
||||
}
|
61
src/main/java/net/md_5/bungee/InitialHandler.java
Normal file
61
src/main/java/net/md_5/bungee/InitialHandler.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
35
src/main/java/net/md_5/bungee/ListenThread.java
Normal file
35
src/main/java/net/md_5/bungee/ListenThread.java
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
20
src/main/java/net/md_5/bungee/ReconnectSaveThread.java
Normal file
20
src/main/java/net/md_5/bungee/ReconnectSaveThread.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
70
src/main/java/net/md_5/bungee/Util.java
Normal file
70
src/main/java/net/md_5/bungee/Util.java
Normal 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();
|
||||
}
|
||||
}
|
88
src/main/java/net/md_5/bungee/packet/DefinedPacket.java
Normal file
88
src/main/java/net/md_5/bungee/packet/DefinedPacket.java
Normal 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();
|
||||
}
|
21
src/main/java/net/md_5/bungee/packet/Packet10HeldItem.java
Normal file
21
src/main/java/net/md_5/bungee/packet/Packet10HeldItem.java
Normal 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();
|
||||
}
|
||||
}
|
30
src/main/java/net/md_5/bungee/packet/Packet2Handshake.java
Normal file
30
src/main/java/net/md_5/bungee/packet/Packet2Handshake.java
Normal 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();
|
||||
}
|
||||
}
|
21
src/main/java/net/md_5/bungee/packet/Packet3Chat.java
Normal file
21
src/main/java/net/md_5/bungee/packet/Packet3Chat.java
Normal 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();
|
||||
}
|
||||
}
|
21
src/main/java/net/md_5/bungee/packet/Packet46GameState.java
Normal file
21
src/main/java/net/md_5/bungee/packet/Packet46GameState.java
Normal 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);
|
||||
}
|
||||
}
|
33
src/main/java/net/md_5/bungee/packet/Packet9Respawn.java
Normal file
33
src/main/java/net/md_5/bungee/packet/Packet9Respawn.java
Normal 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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
21
src/main/java/net/md_5/bungee/packet/PacketFFKick.java
Normal file
21
src/main/java/net/md_5/bungee/packet/PacketFFKick.java
Normal 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();
|
||||
}
|
||||
}
|
48
src/main/java/net/md_5/bungee/packet/PacketInputStream.java
Normal file
48
src/main/java/net/md_5/bungee/packet/PacketInputStream.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
172
src/main/java/net/md_5/bungee/packet/VanillaPackets.java
Normal file
172
src/main/java/net/md_5/bungee/packet/VanillaPackets.java
Normal 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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user