Compare commits
128 Commits
Minecraft-
...
Minecraft-
Author | SHA1 | Date | |
---|---|---|---|
![]() |
db5510cc4e | ||
![]() |
5ed5c71aea | ||
![]() |
38a8469ab4 | ||
![]() |
9538dcf4d4 | ||
![]() |
33f654ce6f | ||
![]() |
c108e4e1ce | ||
![]() |
e998faeec1 | ||
![]() |
d67acd7bc9 | ||
![]() |
702f434db1 | ||
![]() |
47b5631562 | ||
![]() |
80e23d6646 | ||
![]() |
1dca12cffb | ||
![]() |
29c897c9cf | ||
![]() |
042f47cbb9 | ||
![]() |
422e97f495 | ||
![]() |
08789d8f9f | ||
![]() |
96444ae304 | ||
![]() |
af58db8a67 | ||
![]() |
49cffebd9b | ||
![]() |
ffdb917f2c | ||
![]() |
9c9657e36d | ||
![]() |
1342baed47 | ||
![]() |
e3a7490bcd | ||
![]() |
3e8693793c | ||
![]() |
bb47aba682 | ||
![]() |
d0e5ee4e09 | ||
![]() |
07e330b005 | ||
![]() |
024288e587 | ||
![]() |
53a6bb1dee | ||
![]() |
0f06b2c4e0 | ||
![]() |
d3c1acce83 | ||
![]() |
eaea090d37 | ||
![]() |
7384e797fc | ||
![]() |
d4d93ddbb9 | ||
![]() |
ccdf2a89d8 | ||
![]() |
89edb00c05 | ||
![]() |
00a0277a13 | ||
![]() |
68f11e46f7 | ||
![]() |
c352e854ee | ||
![]() |
d8c92cd311 | ||
![]() |
99f361ca77 | ||
![]() |
738ed99d54 | ||
![]() |
ad0da59267 | ||
![]() |
1dcc8d6a4b | ||
![]() |
0840a77153 | ||
![]() |
61a93a54a9 | ||
![]() |
da0281508e | ||
![]() |
51e92de2dd | ||
![]() |
f948acd634 | ||
![]() |
773ce089c1 | ||
![]() |
a07eba7965 | ||
![]() |
b68b6a76c7 | ||
![]() |
332033bb02 | ||
![]() |
172b8bc75b | ||
![]() |
db5a147491 | ||
![]() |
f083e27649 | ||
![]() |
b64a7be19b | ||
![]() |
c4d60a8fa9 | ||
![]() |
f07cfe0cf7 | ||
![]() |
4463b0c1b2 | ||
![]() |
ee8f33c196 | ||
![]() |
14ac2dd308 | ||
![]() |
fb94612315 | ||
![]() |
4c96880580 | ||
![]() |
4c4cdd51a1 | ||
![]() |
1f38152530 | ||
![]() |
911f08d52c | ||
![]() |
8f961c9d4e | ||
![]() |
8a5d8a57f7 | ||
![]() |
c54553d0f9 | ||
![]() |
600a1b4ff5 | ||
![]() |
09e592295f | ||
![]() |
fa0ee02beb | ||
![]() |
b23b54d9e4 | ||
![]() |
b3e8feb4cb | ||
![]() |
d0d1562155 | ||
![]() |
f510ab2a0b | ||
![]() |
fb1cab499d | ||
![]() |
58ca63e2b1 | ||
![]() |
499337c98e | ||
![]() |
526137be7b | ||
![]() |
47839cb11c | ||
![]() |
55a6cc56ef | ||
![]() |
8c2bea5be2 | ||
![]() |
daa58ffe58 | ||
![]() |
0189ad9c17 | ||
![]() |
9adcb05d45 | ||
![]() |
10e81041b2 | ||
![]() |
0c56945ffd | ||
![]() |
0a36cbd5bc | ||
![]() |
61b4777177 | ||
![]() |
7d1904584b | ||
![]() |
475571986c | ||
![]() |
55c2bcd634 | ||
![]() |
db4abfe486 | ||
![]() |
9424bdedca | ||
![]() |
52b3c6b77c | ||
![]() |
be29799f5a | ||
![]() |
c0d581d41f | ||
![]() |
6b50c7c599 | ||
![]() |
b4101874cc | ||
![]() |
66de4c95ef | ||
![]() |
927a295add | ||
![]() |
2cbea83c02 | ||
![]() |
87884ad084 | ||
![]() |
94cc2412e7 | ||
![]() |
924b90e325 | ||
![]() |
3f476a30b4 | ||
![]() |
f579b31bca | ||
![]() |
cac35116c3 | ||
![]() |
bd42fb23a0 | ||
![]() |
ffbebaff69 | ||
![]() |
b741722e5d | ||
![]() |
07288c722c | ||
![]() |
85e82a2e34 | ||
![]() |
3aef35ccbb | ||
![]() |
d1760dad93 | ||
![]() |
d3d11cf283 | ||
![]() |
d3bada58d4 | ||
![]() |
23517a9a97 | ||
![]() |
fdc87e88f5 | ||
![]() |
12941ffe62 | ||
![]() |
06e732d8c7 | ||
![]() |
5c4ea3c7a0 | ||
![]() |
632fa8bd94 | ||
![]() |
8732904bfd | ||
![]() |
788b96dc0a | ||
![]() |
1296783d9b |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,7 +1,7 @@
|
|||||||
# Eclipse stuff
|
# Eclipse stuff
|
||||||
.classpath
|
.classpath
|
||||||
.project
|
.project
|
||||||
.settings
|
.settings/
|
||||||
|
|
||||||
# netbeans
|
# netbeans
|
||||||
nbproject/
|
nbproject/
|
||||||
|
10
api/pom.xml
10
api/pom.xml
@@ -6,13 +6,13 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>bungeecord-parent</artifactId>
|
<artifactId>bungeecord-parent</artifactId>
|
||||||
<version>1.5-SNAPSHOT</version>
|
<version>1.6.2-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>bungeecord-api</artifactId>
|
<artifactId>bungeecord-api</artifactId>
|
||||||
<version>1.5-SNAPSHOT</version>
|
<version>1.6.2-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>BungeeCord-API</name>
|
<name>BungeeCord-API</name>
|
||||||
@@ -25,12 +25,6 @@
|
|||||||
<version>14.0.1</version>
|
<version>14.0.1</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.ning</groupId>
|
|
||||||
<artifactId>async-http-client</artifactId>
|
|
||||||
<version>1.7.17</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>bungeecord-event</artifactId>
|
<artifactId>bungeecord-event</artifactId>
|
||||||
|
@@ -0,0 +1,46 @@
|
|||||||
|
package net.md_5.bungee.api;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import net.md_5.bungee.api.config.ServerInfo;
|
||||||
|
import net.md_5.bungee.api.connection.PendingConnection;
|
||||||
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
|
||||||
|
public abstract class AbstractReconnectHandler implements ReconnectHandler
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ServerInfo getServer(ProxiedPlayer player)
|
||||||
|
{
|
||||||
|
ServerInfo server = getForcedHost( player.getPendingConnection() );
|
||||||
|
if ( server == null )
|
||||||
|
{
|
||||||
|
server = getStoredServer( player );
|
||||||
|
if ( server == null )
|
||||||
|
{
|
||||||
|
server = ProxyServer.getInstance().getServerInfo( player.getPendingConnection().getListener().getDefaultServer() );
|
||||||
|
}
|
||||||
|
|
||||||
|
Preconditions.checkState( server != null, "Default server not defined" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerInfo getForcedHost(PendingConnection con)
|
||||||
|
{
|
||||||
|
if ( con.getVirtualHost() == null )
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String forced = con.getListener().getForcedHosts().get( con.getVirtualHost().getHostString() );
|
||||||
|
|
||||||
|
if ( forced == null && con.getListener().isForceDefault() )
|
||||||
|
{
|
||||||
|
forced = con.getListener().getDefaultServer();
|
||||||
|
}
|
||||||
|
return ProxyServer.getInstance().getServerInfo( forced );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract ServerInfo getStoredServer(ProxiedPlayer player);
|
||||||
|
}
|
@@ -2,7 +2,6 @@ package net.md_5.bungee.api;
|
|||||||
|
|
||||||
import net.md_5.bungee.api.plugin.PluginManager;
|
import net.md_5.bungee.api.plugin.PluginManager;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.ning.http.client.AsyncHttpClient;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -189,10 +188,11 @@ public abstract class ProxyServer
|
|||||||
*
|
*
|
||||||
* @param name name of the server
|
* @param name name of the server
|
||||||
* @param address connectable Minecraft address + port of the server
|
* @param address connectable Minecraft address + port of the server
|
||||||
|
* @param motd the motd when used as a forced server
|
||||||
* @param restricted whether the server info restricted property will be set
|
* @param restricted whether the server info restricted property will be set
|
||||||
* @return the constructed instance
|
* @return the constructed instance
|
||||||
*/
|
*/
|
||||||
public abstract ServerInfo constructServerInfo(String name, InetSocketAddress address, boolean restricted);
|
public abstract ServerInfo constructServerInfo(String name, InetSocketAddress address, String motd, boolean restricted);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the console overlord for this proxy. Being the console, this
|
* Returns the console overlord for this proxy. Being the console, this
|
||||||
@@ -217,15 +217,6 @@ public abstract class ProxyServer
|
|||||||
*/
|
*/
|
||||||
public abstract TaskScheduler getScheduler();
|
public abstract TaskScheduler getScheduler();
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the the web client used by this proxy to facilitate making web
|
|
||||||
* requests. Care should be taken to ensure that all operations are non
|
|
||||||
* blocking where applicable.
|
|
||||||
*
|
|
||||||
* @return the server's {@link AsyncHttpClient} instance
|
|
||||||
*/
|
|
||||||
public abstract AsyncHttpClient getHttpClient();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current number of connected users. The default implementation is
|
* Get the current number of connected users. The default implementation is
|
||||||
* more efficient than {@link #getPlayers()} as it does not take a lock or
|
* more efficient than {@link #getPlayers()} as it does not take a lock or
|
||||||
@@ -249,4 +240,11 @@ public abstract class ProxyServer
|
|||||||
* @return a new {@link CustomTabList} instance
|
* @return a new {@link CustomTabList} instance
|
||||||
*/
|
*/
|
||||||
public abstract CustomTabList customTabList(ProxiedPlayer player);
|
public abstract CustomTabList customTabList(ProxiedPlayer player);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the commands which are disabled and will not be run on this proxy.
|
||||||
|
*
|
||||||
|
* @return the set of disabled commands
|
||||||
|
*/
|
||||||
|
public abstract Collection<String> getDisabledCommands();
|
||||||
}
|
}
|
||||||
|
@@ -43,6 +43,15 @@ public interface ConfigurationAdapter
|
|||||||
*/
|
*/
|
||||||
public boolean getBoolean(String path, boolean def);
|
public boolean getBoolean(String path, boolean def);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list from the specified path.
|
||||||
|
*
|
||||||
|
* @param path the path to retrieve the list form.
|
||||||
|
* @param def the default value
|
||||||
|
* @return the retrieved list
|
||||||
|
*/
|
||||||
|
public Collection<?> getList(String path, Collection<?> def);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the configuration all servers which may be accessible via the proxy.
|
* Get the configuration all servers which may be accessible via the proxy.
|
||||||
*
|
*
|
||||||
|
@@ -48,13 +48,17 @@ public class ListenerInfo
|
|||||||
* transferred depending on the host they connect to.
|
* transferred depending on the host they connect to.
|
||||||
*/
|
*/
|
||||||
private final Map<String, String> forcedHosts;
|
private final Map<String, String> forcedHosts;
|
||||||
/**
|
|
||||||
* Get the texture pack used for servers connected to this proxy. May be
|
|
||||||
* null.
|
|
||||||
*/
|
|
||||||
private final TexturePackInfo texturePack;
|
|
||||||
/**
|
/**
|
||||||
* Class used to build tab lists for this player.
|
* Class used to build tab lists for this player.
|
||||||
*/
|
*/
|
||||||
private final Class<? extends TabListHandler> tabList;
|
private final Class<? extends TabListHandler> tabList;
|
||||||
|
/**
|
||||||
|
* Whether to set the local address when connecting to servers.
|
||||||
|
*/
|
||||||
|
private final boolean setLocalAddress;
|
||||||
|
/**
|
||||||
|
* Whether to pass the ping through when we can reliably get the target
|
||||||
|
* server (force default server).
|
||||||
|
*/
|
||||||
|
private final boolean pingPassthrough;
|
||||||
}
|
}
|
||||||
|
@@ -36,6 +36,13 @@ public interface ServerInfo
|
|||||||
*/
|
*/
|
||||||
Collection<ProxiedPlayer> getPlayers();
|
Collection<ProxiedPlayer> getPlayers();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the MOTD which should be used when this server is a forced host.
|
||||||
|
*
|
||||||
|
* @return the motd
|
||||||
|
*/
|
||||||
|
String getMotd();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the player can access this server. It will only return false when
|
* Whether the player can access this server. It will only return false when
|
||||||
* the player has no permission and this server is restricted.
|
* the player has no permission and this server is restricted.
|
||||||
|
@@ -1,17 +0,0 @@
|
|||||||
package net.md_5.bungee.api.config;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class TexturePackInfo
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The URL of the texture pack.
|
|
||||||
*/
|
|
||||||
private final String url;
|
|
||||||
/**
|
|
||||||
* The square dimension of this texture pack.
|
|
||||||
*/
|
|
||||||
private final int size;
|
|
||||||
}
|
|
@@ -2,7 +2,6 @@ package net.md_5.bungee.api.connection;
|
|||||||
|
|
||||||
import net.md_5.bungee.api.CommandSender;
|
import net.md_5.bungee.api.CommandSender;
|
||||||
import net.md_5.bungee.api.config.ServerInfo;
|
import net.md_5.bungee.api.config.ServerInfo;
|
||||||
import net.md_5.bungee.api.config.TexturePackInfo;
|
|
||||||
import net.md_5.bungee.api.tab.TabListHandler;
|
import net.md_5.bungee.api.tab.TabListHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,13 +71,6 @@ public interface ProxiedPlayer extends Connection, CommandSender
|
|||||||
*/
|
*/
|
||||||
void chat(String message);
|
void chat(String message);
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a request to change the players texture pack.
|
|
||||||
*
|
|
||||||
* @param pack the pack to request
|
|
||||||
*/
|
|
||||||
void setTexturePack(TexturePackInfo pack);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the new tab list for the user. At this stage it is not advisable to
|
* Sets the new tab list for the user. At this stage it is not advisable to
|
||||||
* change after the user has logged in!
|
* change after the user has logged in!
|
||||||
@@ -93,4 +85,18 @@ public interface ProxiedPlayer extends Connection, CommandSender
|
|||||||
* @return the tab list in use by this user
|
* @return the tab list in use by this user
|
||||||
*/
|
*/
|
||||||
TabListHandler getTabList();
|
TabListHandler getTabList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the server which this player will be sent to next time the log in.
|
||||||
|
*
|
||||||
|
* @return the server, or null if default
|
||||||
|
*/
|
||||||
|
ServerInfo getReconnectServer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the server which this player will be sent to next time the log in.
|
||||||
|
*
|
||||||
|
* @param server the server to set
|
||||||
|
*/
|
||||||
|
void setReconnectServer(ServerInfo server);
|
||||||
}
|
}
|
||||||
|
@@ -33,11 +33,27 @@ public class ServerKickEvent extends Event implements Cancellable
|
|||||||
* Server to send player to if this event is cancelled.
|
* Server to send player to if this event is cancelled.
|
||||||
*/
|
*/
|
||||||
private ServerInfo cancelServer;
|
private ServerInfo cancelServer;
|
||||||
|
/**
|
||||||
|
* State in which the kick occured.
|
||||||
|
*/
|
||||||
|
private State state;
|
||||||
|
|
||||||
|
public enum State
|
||||||
|
{
|
||||||
|
|
||||||
|
CONNECTING, CONNECTED, UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
public ServerKickEvent(ProxiedPlayer player, String kickReason, ServerInfo cancelServer)
|
public ServerKickEvent(ProxiedPlayer player, String kickReason, ServerInfo cancelServer)
|
||||||
|
{
|
||||||
|
this( player, kickReason, cancelServer, State.UNKNOWN );
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerKickEvent(ProxiedPlayer player, String kickReason, ServerInfo cancelServer, State state)
|
||||||
{
|
{
|
||||||
this.player = player;
|
this.player = player;
|
||||||
this.kickReason = kickReason;
|
this.kickReason = kickReason;
|
||||||
this.cancelServer = cancelServer;
|
this.cancelServer = cancelServer;
|
||||||
|
this.state = state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,13 +2,18 @@ package net.md_5.bungee.api.plugin;
|
|||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
|
||||||
public class PluginClassloader extends URLClassLoader
|
public class PluginClassloader extends URLClassLoader
|
||||||
{
|
{
|
||||||
|
|
||||||
private static final Set<PluginClassloader> allLoaders = new HashSet<>();
|
private static final Set<PluginClassloader> allLoaders = new CopyOnWriteArraySet<>();
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
ClassLoader.registerAsParallelCapable();
|
||||||
|
}
|
||||||
|
|
||||||
public PluginClassloader(URL[] urls)
|
public PluginClassloader(URL[] urls)
|
||||||
{
|
{
|
||||||
|
@@ -13,13 +13,12 @@ public class PluginLogger extends Logger
|
|||||||
{
|
{
|
||||||
super( plugin.getClass().getCanonicalName(), null );
|
super( plugin.getClass().getCanonicalName(), null );
|
||||||
pluginName = "[" + plugin.getDescription().getName() + "] ";
|
pluginName = "[" + plugin.getDescription().getName() + "] ";
|
||||||
setParent( ProxyServer.getInstance().getLogger() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void log(LogRecord logRecord)
|
public void log(LogRecord logRecord)
|
||||||
{
|
{
|
||||||
logRecord.setMessage( pluginName + logRecord.getMessage() );
|
logRecord.setMessage( pluginName + logRecord.getMessage() );
|
||||||
super.log( logRecord );
|
ProxyServer.getInstance().getLogger().log( logRecord );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
package net.md_5.bungee.api.plugin;
|
package net.md_5.bungee.api.plugin;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
import com.google.common.eventbus.Subscribe;
|
import com.google.common.eventbus.Subscribe;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -10,7 +12,9 @@ import java.net.URLClassLoader;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
import java.util.jar.JarEntry;
|
import java.util.jar.JarEntry;
|
||||||
@@ -42,12 +46,14 @@ public class PluginManager
|
|||||||
private final Map<String, Plugin> plugins = new LinkedHashMap<>();
|
private final Map<String, Plugin> plugins = new LinkedHashMap<>();
|
||||||
private final Map<String, Command> commandMap = new HashMap<>();
|
private final Map<String, Command> commandMap = new HashMap<>();
|
||||||
private Map<String, PluginDescription> toLoad = new HashMap<>();
|
private Map<String, PluginDescription> toLoad = new HashMap<>();
|
||||||
|
private Multimap<Plugin, Command> commandsByPlugin = ArrayListMultimap.create();
|
||||||
|
private Multimap<Plugin, Listener> listenersByPlugin = ArrayListMultimap.create();
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public PluginManager(ProxyServer proxy)
|
public PluginManager(ProxyServer proxy)
|
||||||
{
|
{
|
||||||
this.proxy = proxy;
|
this.proxy = proxy;
|
||||||
eventBus = new EventBus( proxy.getLogger(), Subscribe.class, EventHandler.class );
|
eventBus = new EventBus( proxy.getLogger() );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -63,6 +69,7 @@ public class PluginManager
|
|||||||
{
|
{
|
||||||
commandMap.put( alias.toLowerCase(), command );
|
commandMap.put( alias.toLowerCase(), command );
|
||||||
}
|
}
|
||||||
|
commandsByPlugin.put( plugin, command );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -73,6 +80,26 @@ public class PluginManager
|
|||||||
public void unregisterCommand(Command command)
|
public void unregisterCommand(Command command)
|
||||||
{
|
{
|
||||||
commandMap.values().remove( command );
|
commandMap.values().remove( command );
|
||||||
|
commandsByPlugin.values().remove( command );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister all commands owned by a {@link Plugin}
|
||||||
|
*
|
||||||
|
* @param plugin the plugin to register the commands of
|
||||||
|
*/
|
||||||
|
public void unregisterCommands(Plugin plugin)
|
||||||
|
{
|
||||||
|
for ( Iterator<Command> it = commandsByPlugin.get( plugin ).iterator(); it.hasNext(); )
|
||||||
|
{
|
||||||
|
commandMap.values().remove( it.next() );
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean dispatchCommand(CommandSender sender, String commandLine)
|
||||||
|
{
|
||||||
|
return dispatchCommand( sender, commandLine, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,10 +110,21 @@ public class PluginManager
|
|||||||
* arguments
|
* arguments
|
||||||
* @return whether the command was handled
|
* @return whether the command was handled
|
||||||
*/
|
*/
|
||||||
public boolean dispatchCommand(CommandSender sender, String commandLine)
|
public boolean dispatchCommand(CommandSender sender, String commandLine, List<String> tabResults)
|
||||||
{
|
{
|
||||||
String[] split = argsSplit.split( commandLine );
|
String[] split = argsSplit.split( commandLine );
|
||||||
Command command = commandMap.get( split[0].toLowerCase() );
|
// Check for chat that only contains " "
|
||||||
|
if ( split.length == 0 )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String commandName = split[0].toLowerCase();
|
||||||
|
if ( proxy.getDisabledCommands().contains( commandName ) )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Command command = commandMap.get( commandName );
|
||||||
if ( command == null )
|
if ( command == null )
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -101,8 +139,17 @@ public class PluginManager
|
|||||||
|
|
||||||
String[] args = Arrays.copyOfRange( split, 1, split.length );
|
String[] args = Arrays.copyOfRange( split, 1, split.length );
|
||||||
try
|
try
|
||||||
|
{
|
||||||
|
if ( tabResults == null )
|
||||||
{
|
{
|
||||||
command.execute( sender, args );
|
command.execute( sender, args );
|
||||||
|
} else if ( command instanceof TabExecutor )
|
||||||
|
{
|
||||||
|
for ( String s : ( (TabExecutor) command ).onTabComplete( sender, args ) )
|
||||||
|
{
|
||||||
|
tabResults.add( s );
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch ( Exception ex )
|
} catch ( Exception ex )
|
||||||
{
|
{
|
||||||
sender.sendMessage( ChatColor.RED + "An internal error occurred whilst executing this command, please check the console log for details." );
|
sender.sendMessage( ChatColor.RED + "An internal error occurred whilst executing this command, please check the console log for details." );
|
||||||
@@ -176,7 +223,7 @@ public class PluginManager
|
|||||||
for ( String dependName : plugin.getDepends() )
|
for ( String dependName : plugin.getDepends() )
|
||||||
{
|
{
|
||||||
PluginDescription depend = toLoad.get( dependName );
|
PluginDescription depend = toLoad.get( dependName );
|
||||||
Boolean dependStatus = depend != null ? pluginStatuses.get( depend ) : Boolean.FALSE;
|
Boolean dependStatus = ( depend != null ) ? pluginStatuses.get( depend ) : Boolean.FALSE;
|
||||||
|
|
||||||
if ( dependStatus == null )
|
if ( dependStatus == null )
|
||||||
{
|
{
|
||||||
@@ -202,7 +249,7 @@ public class PluginManager
|
|||||||
{
|
{
|
||||||
ProxyServer.getInstance().getLogger().log( Level.WARNING, "{0} (required by {1}) is unavailable", new Object[]
|
ProxyServer.getInstance().getLogger().log( Level.WARNING, "{0} (required by {1}) is unavailable", new Object[]
|
||||||
{
|
{
|
||||||
depend.getName(), plugin.getName()
|
String.valueOf( depend.getName() ), plugin.getName()
|
||||||
} );
|
} );
|
||||||
status = false;
|
status = false;
|
||||||
}
|
}
|
||||||
@@ -305,7 +352,7 @@ public class PluginManager
|
|||||||
/**
|
/**
|
||||||
* Register a {@link Listener} for receiving called events. Methods in this
|
* Register a {@link Listener} for receiving called events. Methods in this
|
||||||
* Object which wish to receive events must be annotated with the
|
* Object which wish to receive events must be annotated with the
|
||||||
* {@link Subscribe} annotation.
|
* {@link EventHandler} annotation.
|
||||||
*
|
*
|
||||||
* @param plugin the owning plugin
|
* @param plugin the owning plugin
|
||||||
* @param listener the listener to register events for
|
* @param listener the listener to register events for
|
||||||
@@ -314,14 +361,35 @@ public class PluginManager
|
|||||||
{
|
{
|
||||||
for ( Method method : listener.getClass().getDeclaredMethods() )
|
for ( Method method : listener.getClass().getDeclaredMethods() )
|
||||||
{
|
{
|
||||||
if ( method.isAnnotationPresent( Subscribe.class ) )
|
Preconditions.checkArgument( !method.isAnnotationPresent( Subscribe.class ),
|
||||||
{
|
"Listener %s has registered using deprecated subscribe annotation! Please update to @EventHandler.", listener );
|
||||||
proxy.getLogger().log( Level.WARNING, "Listener " + listener + " has registered using depreceated subscribe annotation!"
|
|
||||||
+ " Please advice author to update to @EventHandler."
|
|
||||||
+ " As a server owner you may safely ignore this.", new Exception() );
|
|
||||||
}
|
}
|
||||||
|
eventBus.register( listener );
|
||||||
|
listenersByPlugin.put( plugin, listener );
|
||||||
}
|
}
|
||||||
|
|
||||||
eventBus.register( listener );
|
/**
|
||||||
|
* Unregister a {@link Listener} so that the events do not reach it anymore.
|
||||||
|
*
|
||||||
|
* @param listener the listener to unregister
|
||||||
|
*/
|
||||||
|
public void unregisterListener(Listener listener)
|
||||||
|
{
|
||||||
|
eventBus.unregister( listener );
|
||||||
|
listenersByPlugin.values().remove( listener );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister all of a Plugin's listener.
|
||||||
|
*
|
||||||
|
* @param plugin
|
||||||
|
*/
|
||||||
|
public void unregisterListeners(Plugin plugin)
|
||||||
|
{
|
||||||
|
for ( Iterator<Listener> it = listenersByPlugin.get( plugin ).iterator(); it.hasNext(); )
|
||||||
|
{
|
||||||
|
eventBus.unregister( it.next() );
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,10 @@
|
|||||||
|
package net.md_5.bungee.api.plugin;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.CommandSender;
|
||||||
|
|
||||||
|
|
||||||
|
public interface TabExecutor
|
||||||
|
{
|
||||||
|
|
||||||
|
public Iterable<String> onTabComplete(CommandSender sender, String[] args);
|
||||||
|
}
|
@@ -1,6 +1,5 @@
|
|||||||
package net.md_5.bungee.api.scheduler;
|
package net.md_5.bungee.api.scheduler;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,11 +30,7 @@ public interface ScheduledTask
|
|||||||
Runnable getTask();
|
Runnable getTask();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the delay in the specified unit before this task will next be
|
* Cancel this task to suppress subsequent executions.
|
||||||
* executed.
|
|
||||||
*
|
|
||||||
* @param unit the unit to get the delay in
|
|
||||||
* @return the time before the next execution of this task
|
|
||||||
*/
|
*/
|
||||||
long getDelay(TimeUnit unit);
|
void cancel();
|
||||||
}
|
}
|
||||||
|
@@ -6,13 +6,13 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>bungeecord-parent</artifactId>
|
<artifactId>bungeecord-parent</artifactId>
|
||||||
<version>1.4.7-SNAPSHOT</version>
|
<version>1.6.2-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>bungeecord-config</artifactId>
|
<artifactId>bungeecord-config</artifactId>
|
||||||
<version>1.4.7-SNAPSHOT</version>
|
<version>1.6.2-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>BungeeCord-Config</name>
|
<name>BungeeCord-Config</name>
|
||||||
|
@@ -6,24 +6,15 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>bungeecord-parent</artifactId>
|
<artifactId>bungeecord-parent</artifactId>
|
||||||
<version>1.5-SNAPSHOT</version>
|
<version>1.6.2-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>bungeecord-event</artifactId>
|
<artifactId>bungeecord-event</artifactId>
|
||||||
<version>1.5-SNAPSHOT</version>
|
<version>1.6.2-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>BungeeCord-Event</name>
|
<name>BungeeCord-Event</name>
|
||||||
<description>Generic java event dispatching API intended for use with BungeeCord</description>
|
<description>Generic java event dispatching API intended for use with BungeeCord</description>
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<version>4.11</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
</project>
|
||||||
|
@@ -1,11 +1,12 @@
|
|||||||
package net.md_5.bungee.event;
|
package net.md_5.bungee.event;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.locks.ReadWriteLock;
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
@@ -16,35 +17,19 @@ import java.util.logging.Logger;
|
|||||||
public class EventBus
|
public class EventBus
|
||||||
{
|
{
|
||||||
|
|
||||||
private final Map<Class<?>, Map<Object, Method[]>> eventToHandler = new HashMap<>();
|
private final Map<Class<?>, Map<Byte, Map<Object, Method[]>>> byListenerAndPriority = new HashMap<>();
|
||||||
|
private final Map<Class<?>, EventHandlerMethod[]> byEventBaked = new HashMap<>();
|
||||||
private final ReadWriteLock lock = new ReentrantReadWriteLock();
|
private final ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
private final Class<? extends Annotation>[] annotations;
|
|
||||||
|
|
||||||
public EventBus()
|
public EventBus()
|
||||||
{
|
{
|
||||||
this( null, (Class<? extends Annotation>[]) null );
|
this( null );
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventBus(Logger logger)
|
public EventBus(Logger logger)
|
||||||
{
|
|
||||||
this( logger, (Class<? extends Annotation>[]) null );
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public EventBus(Class<? extends Annotation>... annotations)
|
|
||||||
{
|
|
||||||
this( null, annotations );
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public EventBus(Logger logger, Class<? extends Annotation>... annotations)
|
|
||||||
{
|
{
|
||||||
this.logger = ( logger == null ) ? Logger.getGlobal() : logger;
|
this.logger = ( logger == null ) ? Logger.getGlobal() : logger;
|
||||||
this.annotations = ( annotations == null || annotations.length == 0 ) ? new Class[]
|
|
||||||
{
|
|
||||||
EventHandler.class
|
|
||||||
} : annotations;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void post(Object event)
|
public void post(Object event)
|
||||||
@@ -52,16 +37,14 @@ public class EventBus
|
|||||||
lock.readLock().lock();
|
lock.readLock().lock();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Map<Object, Method[]> handlers = eventToHandler.get( event.getClass() );
|
EventHandlerMethod[] handlers = byEventBaked.get( event.getClass() );
|
||||||
if ( handlers != null )
|
if ( handlers != null )
|
||||||
{
|
{
|
||||||
for ( Map.Entry<Object, Method[]> handler : handlers.entrySet() )
|
for ( EventHandlerMethod method : handlers )
|
||||||
{
|
|
||||||
for ( Method method : handler.getValue() )
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
method.invoke( handler.getKey(), event );
|
method.invoke( event );
|
||||||
} catch ( IllegalAccessException ex )
|
} catch ( IllegalAccessException ex )
|
||||||
{
|
{
|
||||||
throw new Error( "Method became inaccessible: " + event, ex );
|
throw new Error( "Method became inaccessible: " + event, ex );
|
||||||
@@ -70,8 +53,7 @@ public class EventBus
|
|||||||
throw new Error( "Method rejected target/argument: " + event, ex );
|
throw new Error( "Method rejected target/argument: " + event, ex );
|
||||||
} catch ( InvocationTargetException ex )
|
} catch ( InvocationTargetException ex )
|
||||||
{
|
{
|
||||||
logger.log( Level.WARNING, MessageFormat.format( "Error dispatching event {0} to listener {1}", event, handler.getKey() ), ex.getCause() );
|
logger.log( Level.WARNING, MessageFormat.format( "Error dispatching event {0} to listener {1}", event, method.getListener() ), ex.getCause() );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,14 +63,13 @@ public class EventBus
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<Class<?>, Set<Method>> findHandlers(Object listener)
|
private Map<Class<?>, Map<Byte, Set<Method>>> findHandlers(Object listener)
|
||||||
{
|
{
|
||||||
Map<Class<?>, Set<Method>> handler = new HashMap<>();
|
Map<Class<?>, Map<Byte, Set<Method>>> handler = new HashMap<>();
|
||||||
for ( Method m : listener.getClass().getDeclaredMethods() )
|
for ( Method m : listener.getClass().getDeclaredMethods() )
|
||||||
{
|
{
|
||||||
for ( Class<? extends Annotation> annotation : annotations )
|
EventHandler annotation = m.getAnnotation( EventHandler.class );
|
||||||
{
|
if ( annotation != null )
|
||||||
if ( m.isAnnotationPresent( annotation ) )
|
|
||||||
{
|
{
|
||||||
Class<?>[] params = m.getParameterTypes();
|
Class<?>[] params = m.getParameterTypes();
|
||||||
if ( params.length != 1 )
|
if ( params.length != 1 )
|
||||||
@@ -99,16 +80,19 @@ public class EventBus
|
|||||||
} );
|
} );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
Map<Byte, Set<Method>> prioritiesMap = handler.get( params[0] );
|
||||||
Set<Method> existing = handler.get( params[0] );
|
if ( prioritiesMap == null )
|
||||||
if ( existing == null )
|
|
||||||
{
|
{
|
||||||
existing = new HashSet<>();
|
prioritiesMap = new HashMap<>();
|
||||||
handler.put( params[0], existing );
|
handler.put( params[0], prioritiesMap );
|
||||||
}
|
}
|
||||||
existing.add( m );
|
Set<Method> priority = prioritiesMap.get( annotation.priority() );
|
||||||
break;
|
if ( priority == null )
|
||||||
|
{
|
||||||
|
priority = new HashSet<>();
|
||||||
|
prioritiesMap.put( annotation.priority(), priority );
|
||||||
}
|
}
|
||||||
|
priority.add( m );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return handler;
|
return handler;
|
||||||
@@ -116,20 +100,30 @@ public class EventBus
|
|||||||
|
|
||||||
public void register(Object listener)
|
public void register(Object listener)
|
||||||
{
|
{
|
||||||
Map<Class<?>, Set<Method>> handler = findHandlers( listener );
|
Map<Class<?>, Map<Byte, Set<Method>>> handler = findHandlers( listener );
|
||||||
lock.writeLock().lock();
|
lock.writeLock().lock();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
for ( Map.Entry<Class<?>, Set<Method>> e : handler.entrySet() )
|
for ( Map.Entry<Class<?>, Map<Byte, Set<Method>>> e : handler.entrySet() )
|
||||||
{
|
{
|
||||||
Map<Object, Method[]> a = eventToHandler.get( e.getKey() );
|
Map<Byte, Map<Object, Method[]>> prioritiesMap = byListenerAndPriority.get( e.getKey() );
|
||||||
if ( a == null )
|
if ( prioritiesMap == null )
|
||||||
{
|
{
|
||||||
a = new HashMap<>();
|
prioritiesMap = new HashMap<>();
|
||||||
eventToHandler.put( e.getKey(), a );
|
byListenerAndPriority.put( e.getKey(), prioritiesMap );
|
||||||
}
|
}
|
||||||
Method[] baked = new Method[ e.getValue().size() ];
|
for ( Map.Entry<Byte, Set<Method>> entry : e.getValue().entrySet() )
|
||||||
a.put( listener, e.getValue().toArray( baked ) );
|
{
|
||||||
|
Map<Object, Method[]> currentPriorityMap = prioritiesMap.get( entry.getKey() );
|
||||||
|
if ( currentPriorityMap == null )
|
||||||
|
{
|
||||||
|
currentPriorityMap = new HashMap<>();
|
||||||
|
prioritiesMap.put( entry.getKey(), currentPriorityMap );
|
||||||
|
}
|
||||||
|
Method[] baked = new Method[ entry.getValue().size() ];
|
||||||
|
currentPriorityMap.put( listener, entry.getValue().toArray( baked ) );
|
||||||
|
}
|
||||||
|
bakeHandlers( e.getKey() );
|
||||||
}
|
}
|
||||||
} finally
|
} finally
|
||||||
{
|
{
|
||||||
@@ -139,25 +133,70 @@ public class EventBus
|
|||||||
|
|
||||||
public void unregister(Object listener)
|
public void unregister(Object listener)
|
||||||
{
|
{
|
||||||
Map<Class<?>, Set<Method>> handler = findHandlers( listener );
|
Map<Class<?>, Map<Byte, Set<Method>>> handler = findHandlers( listener );
|
||||||
lock.writeLock().lock();
|
lock.writeLock().lock();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
for ( Map.Entry<Class<?>, Set<Method>> e : handler.entrySet() )
|
for ( Map.Entry<Class<?>, Map<Byte, Set<Method>>> e : handler.entrySet() )
|
||||||
{
|
{
|
||||||
Map<Object, Method[]> a = eventToHandler.get( e.getKey() );
|
Map<Byte, Map<Object, Method[]>> prioritiesMap = byListenerAndPriority.get( e.getKey() );
|
||||||
if ( a != null )
|
if ( prioritiesMap != null )
|
||||||
{
|
{
|
||||||
a.remove( listener );
|
for ( Byte priority : e.getValue().keySet() )
|
||||||
if ( a.isEmpty() )
|
|
||||||
{
|
{
|
||||||
eventToHandler.remove( e.getKey() );
|
Map<Object, Method[]> currentPriority = prioritiesMap.get( priority );
|
||||||
|
if ( currentPriority != null )
|
||||||
|
{
|
||||||
|
currentPriority.remove( listener );
|
||||||
|
if ( currentPriority.isEmpty() )
|
||||||
|
{
|
||||||
|
prioritiesMap.remove( priority );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ( prioritiesMap.isEmpty() )
|
||||||
|
{
|
||||||
|
byListenerAndPriority.remove( e.getKey() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bakeHandlers( e.getKey() );
|
||||||
|
}
|
||||||
} finally
|
} finally
|
||||||
{
|
{
|
||||||
lock.writeLock().unlock();
|
lock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shouldn't be called without first locking the writeLock; intended for use
|
||||||
|
* only inside {@link #register(java.lang.Object) register(Object)} or
|
||||||
|
* {@link #unregister(java.lang.Object) unregister(Object)}.
|
||||||
|
*/
|
||||||
|
private void bakeHandlers(Class<?> eventClass)
|
||||||
|
{
|
||||||
|
Map<Byte, Map<Object, Method[]>> handlersByPriority = byListenerAndPriority.get( eventClass );
|
||||||
|
if ( handlersByPriority != null )
|
||||||
|
{
|
||||||
|
List<EventHandlerMethod> handlersList = new ArrayList<>( handlersByPriority.size() * 2 );
|
||||||
|
for ( byte value = Byte.MIN_VALUE; value < Byte.MAX_VALUE; value++ )
|
||||||
|
{
|
||||||
|
Map<Object, Method[]> handlersByListener = handlersByPriority.get( value );
|
||||||
|
if ( handlersByListener != null )
|
||||||
|
{
|
||||||
|
for ( Map.Entry<Object, Method[]> listenerHandlers : handlersByListener.entrySet() )
|
||||||
|
{
|
||||||
|
for ( Method method : listenerHandlers.getValue() )
|
||||||
|
{
|
||||||
|
EventHandlerMethod ehm = new EventHandlerMethod( listenerHandlers.getKey(), method );
|
||||||
|
handlersList.add( ehm );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
byEventBaked.put( eventClass, handlersList.toArray( new EventHandlerMethod[ handlersList.size() ] ) );
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
byEventBaked.put( eventClass, null );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,4 +9,18 @@ import java.lang.annotation.Target;
|
|||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
public @interface EventHandler
|
public @interface EventHandler
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the priority of the event handler.
|
||||||
|
* <p>
|
||||||
|
* Event handlers are called in order of priority:
|
||||||
|
* <ol>
|
||||||
|
* <li>LOWEST</li>
|
||||||
|
* <li>LOW</li>
|
||||||
|
* <li>NORMAL</li>
|
||||||
|
* <li>HIGH</li>
|
||||||
|
* <li>HIGHEST</li>
|
||||||
|
* </ol>
|
||||||
|
*/
|
||||||
|
byte priority() default EventPriority.NORMAL;
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,21 @@
|
|||||||
|
package net.md_5.bungee.event;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class EventHandlerMethod
|
||||||
|
{
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final Object listener;
|
||||||
|
@Getter
|
||||||
|
private final Method method;
|
||||||
|
|
||||||
|
public void invoke(Object event) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
|
||||||
|
{
|
||||||
|
method.invoke( listener, event );
|
||||||
|
}
|
||||||
|
}
|
19
event/src/main/java/net/md_5/bungee/event/EventPriority.java
Normal file
19
event/src/main/java/net/md_5/bungee/event/EventPriority.java
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package net.md_5.bungee.event;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Importance of the {@link EventHandler}. When executing an Event, the handlers
|
||||||
|
* are called in order of their Priority.
|
||||||
|
*/
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class EventPriority
|
||||||
|
{
|
||||||
|
|
||||||
|
public static final byte LOWEST = -64;
|
||||||
|
public static final byte LOW = -32;
|
||||||
|
public static final byte NORMAL = 0;
|
||||||
|
public static final byte HIGH = 32;
|
||||||
|
public static final byte HIGHEST = 64;
|
||||||
|
}
|
@@ -15,14 +15,14 @@ public class EventBusTest
|
|||||||
{
|
{
|
||||||
bus.register( this );
|
bus.register( this );
|
||||||
bus.post( new FirstEvent() );
|
bus.post( new FirstEvent() );
|
||||||
Assert.assertEquals( latch.getCount(), 0 );
|
Assert.assertEquals( 0, latch.getCount() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void firstListener(FirstEvent event)
|
public void firstListener(FirstEvent event)
|
||||||
{
|
{
|
||||||
bus.post( new SecondEvent() );
|
bus.post( new SecondEvent() );
|
||||||
Assert.assertEquals( latch.getCount(), 1 );
|
Assert.assertEquals( 1, latch.getCount() );
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,64 @@
|
|||||||
|
package net.md_5.bungee.event;
|
||||||
|
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class EventPriorityTest
|
||||||
|
{
|
||||||
|
|
||||||
|
private final EventBus bus = new EventBus();
|
||||||
|
private final CountDownLatch latch = new CountDownLatch( 5 );
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPriority()
|
||||||
|
{
|
||||||
|
bus.register( this );
|
||||||
|
bus.register( new EventPriorityListenerPartner() );
|
||||||
|
bus.post( new PriorityTestEvent() );
|
||||||
|
Assert.assertEquals( 0, latch.getCount() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
|
public void onLowestPriority(PriorityTestEvent event)
|
||||||
|
{
|
||||||
|
Assert.assertEquals( 5, latch.getCount() );
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onNormalPriority(PriorityTestEvent event)
|
||||||
|
{
|
||||||
|
Assert.assertEquals( 3, latch.getCount() );
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
|
public void onHighestPriority(PriorityTestEvent event)
|
||||||
|
{
|
||||||
|
Assert.assertEquals( 1, latch.getCount() );
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PriorityTestEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventPriorityListenerPartner
|
||||||
|
{
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.HIGH)
|
||||||
|
public void onHighPriority(PriorityTestEvent event)
|
||||||
|
{
|
||||||
|
Assert.assertEquals( 2, latch.getCount() );
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOW)
|
||||||
|
public void onLowPriority(PriorityTestEvent event)
|
||||||
|
{
|
||||||
|
Assert.assertEquals( 4, latch.getCount() );
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,28 @@
|
|||||||
|
package net.md_5.bungee.event;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class UnregisteringListenerTest
|
||||||
|
{
|
||||||
|
|
||||||
|
private final EventBus bus = new EventBus();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPriority()
|
||||||
|
{
|
||||||
|
bus.register( this );
|
||||||
|
bus.unregister( this );
|
||||||
|
bus.post( new TestEvent() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onEvent(TestEvent evt)
|
||||||
|
{
|
||||||
|
Assert.fail( "Event listener wasn't unregistered" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TestEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
18
pom.xml
18
pom.xml
@@ -11,16 +11,16 @@
|
|||||||
|
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>bungeecord-parent</artifactId>
|
<artifactId>bungeecord-parent</artifactId>
|
||||||
<version>1.5-SNAPSHOT</version>
|
<version>1.6.2-SNAPSHOT</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<name>BungeeCord</name>
|
<name>BungeeCord</name>
|
||||||
<description>Parent project for all BungeeCord modules.</description>
|
<description>Parent project for all BungeeCord modules.</description>
|
||||||
<url>https://github.com/ElasticPortalSuite/BungeeCord</url>
|
<url>https://github.com/SpigotMC/BungeeCord</url>
|
||||||
<inceptionYear>2012</inceptionYear>
|
<inceptionYear>2012</inceptionYear>
|
||||||
<organization>
|
<organization>
|
||||||
<name>Elastic Portal Suite</name>
|
<name>Elastic Portal Suite</name>
|
||||||
<url>https://github.com/ElasticPortalSuite</url>
|
<url>https://github.com/SpigotMC</url>
|
||||||
</organization>
|
</organization>
|
||||||
<licenses>
|
<licenses>
|
||||||
<license>
|
<license>
|
||||||
@@ -44,13 +44,13 @@
|
|||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<scm>
|
<scm>
|
||||||
<connection>scm:git:git@github.com:ElasticPortalSuite/BungeeCord.git</connection>
|
<connection>scm:git:git@github.com:SpigotMC/BungeeCord.git</connection>
|
||||||
<developerConnection>scm:git:git@github.com:ElasticPortalSuite/BungeeCord.git</developerConnection>
|
<developerConnection>scm:git:git@github.com:SpigotMC/BungeeCord.git</developerConnection>
|
||||||
<url>git@github.com:ElasticPortalSuite/BungeeCord.git</url>
|
<url>git@github.com:SpigotMC/BungeeCord.git</url>
|
||||||
</scm>
|
</scm>
|
||||||
<issueManagement>
|
<issueManagement>
|
||||||
<system>GitHub</system>
|
<system>GitHub</system>
|
||||||
<url>https://github.com/ElasticPortalSuite/BungeeCord/issues</url>
|
<url>https://github.com/SpigotMC/BungeeCord/issues</url>
|
||||||
</issueManagement>
|
</issueManagement>
|
||||||
<ciManagement>
|
<ciManagement>
|
||||||
<system>jenkins</system>
|
<system>jenkins</system>
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<build.number>unknown</build.number>
|
<build.number>unknown</build.number>
|
||||||
<netty.version>4.0.0.CR7</netty.version>
|
<netty.version>4.0.9.Final</netty.version>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
<version>0.11.8</version>
|
<version>0.12.0</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@@ -6,13 +6,13 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>bungeecord-parent</artifactId>
|
<artifactId>bungeecord-parent</artifactId>
|
||||||
<version>1.5-SNAPSHOT</version>
|
<version>1.6.2-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>bungeecord-protocol</artifactId>
|
<artifactId>bungeecord-protocol</artifactId>
|
||||||
<version>1.5-SNAPSHOT</version>
|
<version>1.6.2-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>BungeeCord-Protocol</name>
|
<name>BungeeCord-Protocol</name>
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-buffer</artifactId>
|
<artifactId>netty-buffer</artifactId>
|
||||||
<version>${netty.version}</version>
|
<version>${netty.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
@@ -0,0 +1,38 @@
|
|||||||
|
package net.md_5.bungee.protocol;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MinecraftInput
|
||||||
|
{
|
||||||
|
|
||||||
|
private final ByteBuf buf;
|
||||||
|
|
||||||
|
public byte readByte()
|
||||||
|
{
|
||||||
|
return buf.readByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
public short readUnisgnedByte()
|
||||||
|
{
|
||||||
|
return buf.readUnsignedByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readInt()
|
||||||
|
{
|
||||||
|
return buf.readInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String readString()
|
||||||
|
{
|
||||||
|
short len = buf.readShort();
|
||||||
|
char[] c = new char[ len ];
|
||||||
|
for ( int i = 0; i < c.length; i++ )
|
||||||
|
{
|
||||||
|
c[i] = buf.readChar();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new String( c );
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,56 @@
|
|||||||
|
package net.md_5.bungee.protocol;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class MinecraftOutput
|
||||||
|
{
|
||||||
|
|
||||||
|
private final ByteBuf buf;
|
||||||
|
|
||||||
|
public MinecraftOutput()
|
||||||
|
{
|
||||||
|
buf = Unpooled.buffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] toArray()
|
||||||
|
{
|
||||||
|
if ( buf.hasArray() )
|
||||||
|
{
|
||||||
|
return Arrays.copyOfRange( buf.array(), buf.arrayOffset(), buf.arrayOffset() + buf.writerIndex() );
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
byte[] b = new byte[ buf.writerIndex() ];
|
||||||
|
buf.readBytes( b );
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MinecraftOutput writeByte(byte b)
|
||||||
|
{
|
||||||
|
buf.writeByte( b );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeInt(int i)
|
||||||
|
{
|
||||||
|
buf.writeInt( i );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeString(String s)
|
||||||
|
{
|
||||||
|
char[] cc = s.toCharArray();
|
||||||
|
buf.writeShort( cc.length );
|
||||||
|
for ( char c : cc )
|
||||||
|
{
|
||||||
|
buf.writeChar( c );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeStringUTF8WithoutLengthHeaderBecauseDinnerboneStuffedUpTheMCBrandPacket(String s)
|
||||||
|
{
|
||||||
|
buf.writeBytes( s.getBytes( Charset.forName( "UTF-8" ) ) );
|
||||||
|
}
|
||||||
|
}
|
@@ -3,5 +3,5 @@ package net.md_5.bungee.protocol;
|
|||||||
public enum OpCode
|
public enum OpCode
|
||||||
{
|
{
|
||||||
|
|
||||||
BOOLEAN, BULK_CHUNK, BYTE, BYTE_INT, DOUBLE, FLOAT, INT, INT_3, INT_BYTE, ITEM, LONG, METADATA, OPTIONAL_MOTION, SHORT, SHORT_BYTE, SHORT_ITEM, STRING, USHORT_BYTE
|
BOOLEAN, BULK_CHUNK, BYTE, BYTE_INT, DOUBLE, FLOAT, INT, INT_3, INT_BYTE, ITEM, LONG, METADATA, OPTIONAL_MOTION, SHORT, SHORT_BYTE, SHORT_ITEM, STRING, USHORT_BYTE, OPTIONAL_WINDOW
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
package net.md_5.bungee.protocol;
|
package net.md_5.bungee.protocol;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -9,10 +8,12 @@ import static net.md_5.bungee.protocol.OpCode.*;
|
|||||||
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
||||||
import net.md_5.bungee.protocol.packet.Packet0KeepAlive;
|
import net.md_5.bungee.protocol.packet.Packet0KeepAlive;
|
||||||
import net.md_5.bungee.protocol.packet.Packet1Login;
|
import net.md_5.bungee.protocol.packet.Packet1Login;
|
||||||
|
import net.md_5.bungee.protocol.packet.Packet2CEntityProperties;
|
||||||
import net.md_5.bungee.protocol.packet.Packet2Handshake;
|
import net.md_5.bungee.protocol.packet.Packet2Handshake;
|
||||||
import net.md_5.bungee.protocol.packet.Packet3Chat;
|
import net.md_5.bungee.protocol.packet.Packet3Chat;
|
||||||
import net.md_5.bungee.protocol.packet.Packet9Respawn;
|
import net.md_5.bungee.protocol.packet.Packet9Respawn;
|
||||||
import net.md_5.bungee.protocol.packet.PacketC9PlayerListItem;
|
import net.md_5.bungee.protocol.packet.PacketC9PlayerListItem;
|
||||||
|
import net.md_5.bungee.protocol.packet.PacketCBTabComplete;
|
||||||
import net.md_5.bungee.protocol.packet.PacketCCSettings;
|
import net.md_5.bungee.protocol.packet.PacketCCSettings;
|
||||||
import net.md_5.bungee.protocol.packet.PacketCDClientStatus;
|
import net.md_5.bungee.protocol.packet.PacketCDClientStatus;
|
||||||
import net.md_5.bungee.protocol.packet.PacketCEScoreboardObjective;
|
import net.md_5.bungee.protocol.packet.PacketCEScoreboardObjective;
|
||||||
@@ -29,8 +30,8 @@ import net.md_5.bungee.protocol.skip.PacketReader;
|
|||||||
public class Vanilla implements Protocol
|
public class Vanilla implements Protocol
|
||||||
{
|
{
|
||||||
|
|
||||||
public static final byte PROTOCOL_VERSION = 61;
|
public static final byte PROTOCOL_VERSION = 74;
|
||||||
public static final String GAME_VERSION = "1.5.2";
|
public static final String GAME_VERSION = "1.6.2";
|
||||||
@Getter
|
@Getter
|
||||||
private static final Vanilla instance = new Vanilla();
|
private static final Vanilla instance = new Vanilla();
|
||||||
/*========================================================================*/
|
/*========================================================================*/
|
||||||
@@ -54,7 +55,9 @@ public class Vanilla implements Protocol
|
|||||||
classes[0x03] = Packet3Chat.class;
|
classes[0x03] = Packet3Chat.class;
|
||||||
classes[0x09] = Packet9Respawn.class;
|
classes[0x09] = Packet9Respawn.class;
|
||||||
classes[0xC9] = PacketC9PlayerListItem.class;
|
classes[0xC9] = PacketC9PlayerListItem.class;
|
||||||
|
classes[0x2C] = Packet2CEntityProperties.class;
|
||||||
classes[0xCC] = PacketCCSettings.class;
|
classes[0xCC] = PacketCCSettings.class;
|
||||||
|
classes[0xCB] = PacketCBTabComplete.class;
|
||||||
classes[0xCD] = PacketCDClientStatus.class;
|
classes[0xCD] = PacketCDClientStatus.class;
|
||||||
classes[0xCE] = PacketCEScoreboardObjective.class;
|
classes[0xCE] = PacketCEScoreboardObjective.class;
|
||||||
classes[0xCF] = PacketCFScoreboardScore.class;
|
classes[0xCF] = PacketCFScoreboardScore.class;
|
||||||
@@ -141,7 +144,7 @@ public class Vanilla implements Protocol
|
|||||||
};
|
};
|
||||||
opCodes[0x08] = new OpCode[]
|
opCodes[0x08] = new OpCode[]
|
||||||
{
|
{
|
||||||
SHORT, SHORT, FLOAT
|
FLOAT, SHORT, FLOAT
|
||||||
};
|
};
|
||||||
opCodes[0x0A] = new OpCode[]
|
opCodes[0x0A] = new OpCode[]
|
||||||
{
|
{
|
||||||
@@ -181,7 +184,7 @@ public class Vanilla implements Protocol
|
|||||||
};
|
};
|
||||||
opCodes[0x13] = new OpCode[]
|
opCodes[0x13] = new OpCode[]
|
||||||
{
|
{
|
||||||
INT, BYTE
|
INT, BYTE, INT
|
||||||
};
|
};
|
||||||
opCodes[0x14] = new OpCode[]
|
opCodes[0x14] = new OpCode[]
|
||||||
{
|
{
|
||||||
@@ -207,6 +210,10 @@ public class Vanilla implements Protocol
|
|||||||
{
|
{
|
||||||
INT, INT, INT, INT, SHORT
|
INT, INT, INT, INT, SHORT
|
||||||
};
|
};
|
||||||
|
opCodes[0x1B] = new OpCode[]
|
||||||
|
{
|
||||||
|
FLOAT, FLOAT, BOOLEAN, BOOLEAN
|
||||||
|
};
|
||||||
opCodes[0x1C] = new OpCode[]
|
opCodes[0x1C] = new OpCode[]
|
||||||
{
|
{
|
||||||
INT, SHORT, SHORT, SHORT
|
INT, SHORT, SHORT, SHORT
|
||||||
@@ -245,7 +252,7 @@ public class Vanilla implements Protocol
|
|||||||
};
|
};
|
||||||
opCodes[0x27] = new OpCode[]
|
opCodes[0x27] = new OpCode[]
|
||||||
{
|
{
|
||||||
INT, INT
|
INT, INT, BOOLEAN
|
||||||
};
|
};
|
||||||
opCodes[0x28] = new OpCode[]
|
opCodes[0x28] = new OpCode[]
|
||||||
{
|
{
|
||||||
@@ -313,7 +320,7 @@ public class Vanilla implements Protocol
|
|||||||
};
|
};
|
||||||
opCodes[0x64] = new OpCode[]
|
opCodes[0x64] = new OpCode[]
|
||||||
{
|
{
|
||||||
BYTE, BYTE, STRING, BYTE, BOOLEAN
|
OPTIONAL_WINDOW
|
||||||
};
|
};
|
||||||
opCodes[0x65] = new OpCode[]
|
opCodes[0x65] = new OpCode[]
|
||||||
{
|
{
|
||||||
@@ -359,17 +366,21 @@ public class Vanilla implements Protocol
|
|||||||
{
|
{
|
||||||
INT, SHORT, INT, BYTE, SHORT_BYTE
|
INT, SHORT, INT, BYTE, SHORT_BYTE
|
||||||
};
|
};
|
||||||
|
opCodes[0x85] = new OpCode[]
|
||||||
|
{
|
||||||
|
BYTE, INT, INT, INT
|
||||||
|
};
|
||||||
opCodes[0xC3] = new OpCode[]
|
opCodes[0xC3] = new OpCode[]
|
||||||
{
|
{
|
||||||
SHORT, SHORT, INT_BYTE
|
SHORT, SHORT, INT_BYTE
|
||||||
};
|
};
|
||||||
opCodes[0xC8] = new OpCode[]
|
opCodes[0xC8] = new OpCode[]
|
||||||
{
|
{
|
||||||
INT, BYTE
|
INT, INT
|
||||||
};
|
};
|
||||||
opCodes[0xCA] = new OpCode[]
|
opCodes[0xCA] = new OpCode[]
|
||||||
{
|
{
|
||||||
BYTE, BYTE, BYTE
|
BYTE, FLOAT, FLOAT
|
||||||
};
|
};
|
||||||
opCodes[0xCB] = new OpCode[]
|
opCodes[0xCB] = new OpCode[]
|
||||||
{
|
{
|
||||||
|
@@ -23,6 +23,10 @@ public abstract class AbstractPacketHandler
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void handle(Packet2CEntityProperties properties) throws Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public void handle(PacketC9PlayerListItem playerList) throws Exception
|
public void handle(PacketC9PlayerListItem playerList) throws Exception
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -70,4 +74,8 @@ public abstract class AbstractPacketHandler
|
|||||||
public void handle(PacketFFKick kick) throws Exception
|
public void handle(PacketFFKick kick) throws Exception
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void handle(PacketCBTabComplete tabComplete) throws Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,49 @@
|
|||||||
|
package net.md_5.bungee.protocol.packet;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class Packet2CEntityProperties extends DefinedPacket
|
||||||
|
{
|
||||||
|
|
||||||
|
public Packet2CEntityProperties()
|
||||||
|
{
|
||||||
|
super( 0x2C );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(ByteBuf buf)
|
||||||
|
{
|
||||||
|
buf.readInt();
|
||||||
|
int recordCount = buf.readInt();
|
||||||
|
for ( int i = 0; i < recordCount; i++ )
|
||||||
|
{
|
||||||
|
readString( buf );
|
||||||
|
buf.readDouble();
|
||||||
|
short size = buf.readShort();
|
||||||
|
for ( short s = 0; s < size; s++ )
|
||||||
|
{
|
||||||
|
buf.skipBytes( 25 ); // long, long, double, byte
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(ByteBuf buf)
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(AbstractPacketHandler handler) throws Exception
|
||||||
|
{
|
||||||
|
handler.handle( this );
|
||||||
|
}
|
||||||
|
}
|
@@ -3,9 +3,11 @@ package net.md_5.bungee.protocol.packet;
|
|||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
@Setter
|
||||||
@ToString
|
@ToString
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
public class Packet3Chat extends DefinedPacket
|
public class Packet3Chat extends DefinedPacket
|
||||||
|
@@ -41,7 +41,7 @@ public class PacketC9PlayerListItem extends DefinedPacket
|
|||||||
{
|
{
|
||||||
writeString( username, buf );
|
writeString( username, buf );
|
||||||
buf.writeBoolean( online );
|
buf.writeBoolean( online );
|
||||||
buf.writeShort(ping );
|
buf.writeShort( ping );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -0,0 +1,56 @@
|
|||||||
|
package net.md_5.bungee.protocol.packet;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class PacketCBTabComplete extends DefinedPacket
|
||||||
|
{
|
||||||
|
|
||||||
|
private String cursor;
|
||||||
|
private String[] commands;
|
||||||
|
|
||||||
|
private PacketCBTabComplete()
|
||||||
|
{
|
||||||
|
super( 0xCB );
|
||||||
|
}
|
||||||
|
|
||||||
|
public PacketCBTabComplete(String[] alternatives)
|
||||||
|
{
|
||||||
|
this();
|
||||||
|
commands = alternatives;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(ByteBuf buf)
|
||||||
|
{
|
||||||
|
cursor = readString( buf );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(ByteBuf buf)
|
||||||
|
{
|
||||||
|
String tab = "";
|
||||||
|
for ( String alternative : commands )
|
||||||
|
{
|
||||||
|
if ( tab.isEmpty() )
|
||||||
|
{
|
||||||
|
tab = alternative + " ";
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
tab += "\0" + alternative + " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeString( tab, buf );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(AbstractPacketHandler handler) throws Exception
|
||||||
|
{
|
||||||
|
handler.handle( this );
|
||||||
|
}
|
||||||
|
}
|
@@ -1,9 +1,15 @@
|
|||||||
package net.md_5.bungee.protocol.packet;
|
package net.md_5.bungee.protocol.packet;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataInputStream;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
import net.md_5.bungee.protocol.MinecraftInput;
|
||||||
|
import net.md_5.bungee.protocol.MinecraftOutput;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ToString
|
@ToString
|
||||||
@@ -45,4 +51,14 @@ public class PacketFAPluginMessage extends DefinedPacket
|
|||||||
{
|
{
|
||||||
handler.handle( this );
|
handler.handle( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DataInput getStream()
|
||||||
|
{
|
||||||
|
return new DataInputStream( new ByteArrayInputStream( data ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public MinecraftInput getMCStream()
|
||||||
|
{
|
||||||
|
return new MinecraftInput( Unpooled.wrappedBuffer( data ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,7 @@ abstract class Instruction
|
|||||||
static final Instruction SHORT_ITEM = new ShortHeader( ITEM );
|
static final Instruction SHORT_ITEM = new ShortHeader( ITEM );
|
||||||
static final Instruction STRING = new ShortHeader( new Jump( 2 ) );
|
static final Instruction STRING = new ShortHeader( new Jump( 2 ) );
|
||||||
static final Instruction USHORT_BYTE = new UnsignedShortByte();
|
static final Instruction USHORT_BYTE = new UnsignedShortByte();
|
||||||
|
static final Instruction OPTIONAL_WINDOW = new OptionalWindow();
|
||||||
// Illegal forward references below this line
|
// Illegal forward references below this line
|
||||||
static final Instruction BYTE_INT = new ByteHeader( INT );
|
static final Instruction BYTE_INT = new ByteHeader( INT );
|
||||||
// Custom instructions
|
// Custom instructions
|
||||||
|
@@ -0,0 +1,21 @@
|
|||||||
|
package net.md_5.bungee.protocol.skip;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
|
public class OptionalWindow extends Instruction
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void read(ByteBuf in)
|
||||||
|
{
|
||||||
|
BYTE.read( in );
|
||||||
|
byte type = in.readByte();
|
||||||
|
STRING.read( in );
|
||||||
|
BYTE.read( in );
|
||||||
|
BOOLEAN.read( in );
|
||||||
|
if ( type == 11 )
|
||||||
|
{
|
||||||
|
INT.read( in );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -6,28 +6,32 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>bungeecord-parent</artifactId>
|
<artifactId>bungeecord-parent</artifactId>
|
||||||
<version>1.5-SNAPSHOT</version>
|
<version>1.6.2-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>bungeecord-proxy</artifactId>
|
<artifactId>bungeecord-proxy</artifactId>
|
||||||
<version>1.5-SNAPSHOT</version>
|
<version>1.6.2-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>BungeeCord-Proxy</name>
|
<name>BungeeCord-Proxy</name>
|
||||||
<description>Proxy component of the Elastic Portal Suite</description>
|
<description>Proxy component of the Elastic Portal Suite</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.build.timestamp.format>yyyyMMdd</maven.build.timestamp.format>
|
||||||
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>com.google.code.gson</groupId>
|
||||||
<artifactId>netty-codec</artifactId>
|
<artifactId>gson</artifactId>
|
||||||
<version>${netty.version}</version>
|
<version>2.2.4</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-handler</artifactId>
|
<artifactId>netty-codec-http</artifactId>
|
||||||
<version>${netty.version}</version>
|
<version>${netty.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
@@ -58,7 +62,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>mysql</groupId>
|
<groupId>mysql</groupId>
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
<version>5.1.24</version>
|
<version>5.1.25</version>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -67,16 +71,16 @@
|
|||||||
<version>3.18.0-GA</version>
|
<version>3.18.0-GA</version>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.xerial</groupId>
|
|
||||||
<artifactId>sqlite-jdbc</artifactId>
|
|
||||||
<version>3.7.2</version>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<finalName>BungeeCord</finalName>
|
<finalName>BungeeCord</finalName>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<!-- Don't deploy proxy to maven repo, only APIs -->
|
<!-- Don't deploy proxy to maven repo, only APIs -->
|
||||||
@@ -95,6 +99,7 @@
|
|||||||
<manifestEntries>
|
<manifestEntries>
|
||||||
<Main-Class>net.md_5.bungee.BungeeCord</Main-Class>
|
<Main-Class>net.md_5.bungee.BungeeCord</Main-Class>
|
||||||
<Implementation-Version>${describe}</Implementation-Version>
|
<Implementation-Version>${describe}</Implementation-Version>
|
||||||
|
<Specification-Version>${maven.build.timestamp}</Specification-Version>
|
||||||
</manifestEntries>
|
</manifestEntries>
|
||||||
</archive>
|
</archive>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -102,7 +107,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
<version>2.0</version>
|
<version>2.1</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<phase>package</phase>
|
<phase>package</phase>
|
||||||
|
@@ -2,13 +2,10 @@ package net.md_5.bungee;
|
|||||||
|
|
||||||
import com.google.common.io.ByteStreams;
|
import com.google.common.io.ByteStreams;
|
||||||
import net.md_5.bungee.log.BungeeLogger;
|
import net.md_5.bungee.log.BungeeLogger;
|
||||||
import net.md_5.bungee.reconnect.SQLReconnectHandler;
|
import net.md_5.bungee.reconnect.YamlReconnectHandler;
|
||||||
import net.md_5.bungee.scheduler.BungeeScheduler;
|
import net.md_5.bungee.scheduler.BungeeScheduler;
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
import com.ning.http.client.AsyncHttpClient;
|
import com.google.gson.Gson;
|
||||||
import com.ning.http.client.AsyncHttpClientConfig;
|
|
||||||
import com.ning.http.client.providers.netty.NettyAsyncHttpProvider;
|
|
||||||
import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig;
|
|
||||||
import io.netty.bootstrap.ServerBootstrap;
|
import io.netty.bootstrap.ServerBootstrap;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.ChannelException;
|
import io.netty.channel.ChannelException;
|
||||||
@@ -17,11 +14,13 @@ import io.netty.channel.ChannelFutureListener;
|
|||||||
import io.netty.channel.MultithreadEventLoopGroup;
|
import io.netty.channel.MultithreadEventLoopGroup;
|
||||||
import io.netty.channel.nio.NioEventLoopGroup;
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
|
import io.netty.util.ResourceLeakDetector;
|
||||||
import net.md_5.bungee.config.Configuration;
|
import net.md_5.bungee.config.Configuration;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -31,7 +30,6 @@ import java.util.MissingResourceException;
|
|||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.locks.ReadWriteLock;
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
@@ -53,7 +51,6 @@ import net.md_5.bungee.api.config.ServerInfo;
|
|||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
import net.md_5.bungee.api.plugin.PluginManager;
|
import net.md_5.bungee.api.plugin.PluginManager;
|
||||||
import net.md_5.bungee.api.scheduler.TaskScheduler;
|
|
||||||
import net.md_5.bungee.api.tab.CustomTabList;
|
import net.md_5.bungee.api.tab.CustomTabList;
|
||||||
import net.md_5.bungee.command.*;
|
import net.md_5.bungee.command.*;
|
||||||
import net.md_5.bungee.config.YamlConfig;
|
import net.md_5.bungee.config.YamlConfig;
|
||||||
@@ -63,7 +60,6 @@ import net.md_5.bungee.protocol.packet.DefinedPacket;
|
|||||||
import net.md_5.bungee.protocol.packet.Packet3Chat;
|
import net.md_5.bungee.protocol.packet.Packet3Chat;
|
||||||
import net.md_5.bungee.protocol.packet.PacketFAPluginMessage;
|
import net.md_5.bungee.protocol.packet.PacketFAPluginMessage;
|
||||||
import net.md_5.bungee.protocol.Vanilla;
|
import net.md_5.bungee.protocol.Vanilla;
|
||||||
import net.md_5.bungee.scheduler.BungeeThreadPool;
|
|
||||||
import net.md_5.bungee.tab.Custom;
|
import net.md_5.bungee.tab.Custom;
|
||||||
import net.md_5.bungee.util.CaseInsensitiveMap;
|
import net.md_5.bungee.util.CaseInsensitiveMap;
|
||||||
import org.fusesource.jansi.AnsiConsole;
|
import org.fusesource.jansi.AnsiConsole;
|
||||||
@@ -86,11 +82,7 @@ public class BungeeCord extends ProxyServer
|
|||||||
* Localization bundle.
|
* Localization bundle.
|
||||||
*/
|
*/
|
||||||
public final ResourceBundle bundle = ResourceBundle.getBundle( "messages_en" );
|
public final ResourceBundle bundle = ResourceBundle.getBundle( "messages_en" );
|
||||||
/**
|
public final MultithreadEventLoopGroup eventLoops = new NioEventLoopGroup( 0, new ThreadFactoryBuilder().setNameFormat( "Netty IO Thread #%1$d" ).build() );
|
||||||
* Thread pools.
|
|
||||||
*/
|
|
||||||
public final ScheduledThreadPoolExecutor executors = new BungeeThreadPool( new ThreadFactoryBuilder().setNameFormat( "Bungee Pool Thread #%1$d" ).build() );
|
|
||||||
public final MultithreadEventLoopGroup eventLoops = new NioEventLoopGroup( Runtime.getRuntime().availableProcessors(), new ThreadFactoryBuilder().setNameFormat( "Netty IO Thread #%1$d" ).build() );
|
|
||||||
/**
|
/**
|
||||||
* locations.yml save thread.
|
* locations.yml save thread.
|
||||||
*/
|
*/
|
||||||
@@ -120,16 +112,14 @@ public class BungeeCord extends ProxyServer
|
|||||||
@Getter
|
@Getter
|
||||||
private final File pluginsFolder = new File( "plugins" );
|
private final File pluginsFolder = new File( "plugins" );
|
||||||
@Getter
|
@Getter
|
||||||
private final TaskScheduler scheduler = new BungeeScheduler();
|
private final BungeeScheduler scheduler = new BungeeScheduler();
|
||||||
@Getter
|
|
||||||
private final AsyncHttpClient httpClient = new AsyncHttpClient(
|
|
||||||
new NettyAsyncHttpProvider(
|
|
||||||
new AsyncHttpClientConfig.Builder().setAsyncHttpClientProviderConfig(
|
|
||||||
new NettyAsyncHttpProviderConfig().addProperty( NettyAsyncHttpProviderConfig.BOSS_EXECUTOR_SERVICE, executors ) ).setExecutorService( executors ).build() ) );
|
|
||||||
@Getter
|
@Getter
|
||||||
private ConsoleReader consoleReader;
|
private ConsoleReader consoleReader;
|
||||||
@Getter
|
@Getter
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
|
public final Gson gson = new Gson();
|
||||||
|
@Getter
|
||||||
|
private ConnectionThrottle connectionThrottle;
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -177,16 +167,19 @@ public class BungeeCord extends ProxyServer
|
|||||||
* @throws Exception when the server cannot be started
|
* @throws Exception when the server cannot be started
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) throws Exception
|
public static void main(String[] args) throws Exception
|
||||||
|
{
|
||||||
|
if ( BungeeCord.class.getPackage().getSpecificationVersion() != null )
|
||||||
{
|
{
|
||||||
Calendar deadline = Calendar.getInstance();
|
Calendar deadline = Calendar.getInstance();
|
||||||
deadline.set( 2013, 7, 1 ); // year, month, date
|
deadline.add( Calendar.WEEK_OF_YEAR, 2 );
|
||||||
if ( Calendar.getInstance().after( deadline ) )
|
if ( Calendar.getInstance().after( new SimpleDateFormat( "yyyyMMdd" ).parse( BungeeCord.class.getPackage().getSpecificationVersion() ) ) )
|
||||||
{
|
{
|
||||||
System.err.println( "*** Warning, this build is outdated ***" );
|
System.err.println( "*** Warning, this build is outdated ***" );
|
||||||
System.err.println( "*** Please download a new build from http://ci.md-5.net/job/BungeeCord ***" );
|
System.err.println( "*** Please download a new build from http://ci.md-5.net/job/BungeeCord ***" );
|
||||||
System.err.println( "*** You will get NO support regarding this build ***" );
|
System.err.println( "*** You will get NO support regarding this build ***" );
|
||||||
System.err.println( "*** Server will start in 15 seconds ***" );
|
System.err.println( "*** Server will start in 30 seconds ***" );
|
||||||
Thread.sleep( TimeUnit.SECONDS.toMillis( 15 ) );
|
Thread.sleep( TimeUnit.SECONDS.toMillis( 30 ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BungeeCord bungee = new BungeeCord();
|
BungeeCord bungee = new BungeeCord();
|
||||||
@@ -216,26 +209,36 @@ public class BungeeCord extends ProxyServer
|
|||||||
@Override
|
@Override
|
||||||
public void start() throws Exception
|
public void start() throws Exception
|
||||||
{
|
{
|
||||||
|
ResourceLeakDetector.setEnabled( false ); // Eats performance
|
||||||
|
|
||||||
pluginsFolder.mkdir();
|
pluginsFolder.mkdir();
|
||||||
pluginManager.detectPlugins( pluginsFolder );
|
pluginManager.detectPlugins( pluginsFolder );
|
||||||
config.load();
|
config.load();
|
||||||
if ( reconnectHandler == null )
|
for ( ListenerInfo info : config.getListeners() )
|
||||||
{
|
{
|
||||||
reconnectHandler = new SQLReconnectHandler();
|
if ( !info.isForceDefault() && reconnectHandler == null )
|
||||||
|
{
|
||||||
|
reconnectHandler = new YamlReconnectHandler();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
isRunning = true;
|
isRunning = true;
|
||||||
|
|
||||||
pluginManager.loadAndEnablePlugins();
|
pluginManager.loadAndEnablePlugins();
|
||||||
|
|
||||||
|
connectionThrottle = new ConnectionThrottle( config.getThrottle() );
|
||||||
startListeners();
|
startListeners();
|
||||||
|
|
||||||
saveThread.scheduleAtFixedRate( new TimerTask()
|
saveThread.scheduleAtFixedRate( new TimerTask()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void run()
|
public void run()
|
||||||
|
{
|
||||||
|
if ( getReconnectHandler() != null )
|
||||||
{
|
{
|
||||||
getReconnectHandler().save();
|
getReconnectHandler().save();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}, 0, TimeUnit.MINUTES.toMillis( 5 ) );
|
}, 0, TimeUnit.MINUTES.toMillis( 5 ) );
|
||||||
metricsThread.scheduleAtFixedRate( new Metrics(), 0, TimeUnit.MINUTES.toMillis( Metrics.PING_INTERVAL ) );
|
metricsThread.scheduleAtFixedRate( new Metrics(), 0, TimeUnit.MINUTES.toMillis( Metrics.PING_INTERVAL ) );
|
||||||
}
|
}
|
||||||
@@ -295,9 +298,6 @@ public class BungeeCord extends ProxyServer
|
|||||||
{
|
{
|
||||||
BungeeCord.this.isRunning = false;
|
BungeeCord.this.isRunning = false;
|
||||||
|
|
||||||
httpClient.close();
|
|
||||||
executors.shutdown();
|
|
||||||
|
|
||||||
stopListeners();
|
stopListeners();
|
||||||
getLogger().info( "Closing pending connections" );
|
getLogger().info( "Closing pending connections" );
|
||||||
|
|
||||||
@@ -323,20 +323,31 @@ public class BungeeCord extends ProxyServer
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( reconnectHandler != null )
|
||||||
|
{
|
||||||
getLogger().info( "Saving reconnect locations" );
|
getLogger().info( "Saving reconnect locations" );
|
||||||
reconnectHandler.save();
|
reconnectHandler.save();
|
||||||
reconnectHandler.close();
|
reconnectHandler.close();
|
||||||
|
}
|
||||||
saveThread.cancel();
|
saveThread.cancel();
|
||||||
metricsThread.cancel();
|
metricsThread.cancel();
|
||||||
|
|
||||||
// TODO: Fix this shit
|
// TODO: Fix this shit
|
||||||
getLogger().info( "Disabling plugins" );
|
getLogger().info( "Disabling plugins" );
|
||||||
for ( Plugin plugin : pluginManager.getPlugins() )
|
for ( Plugin plugin : pluginManager.getPlugins() )
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
plugin.onDisable();
|
plugin.onDisable();
|
||||||
|
} catch ( Throwable t )
|
||||||
|
{
|
||||||
|
getLogger().severe( "Exception disabling plugin " + plugin.getDescription().getName() );
|
||||||
|
t.printStackTrace();
|
||||||
|
}
|
||||||
getScheduler().cancel( plugin );
|
getScheduler().cancel( plugin );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scheduler.shutdown();
|
||||||
getLogger().info( "Thankyou and goodbye" );
|
getLogger().info( "Thankyou and goodbye" );
|
||||||
System.exit( 0 );
|
System.exit( 0 );
|
||||||
}
|
}
|
||||||
@@ -472,9 +483,9 @@ public class BungeeCord extends ProxyServer
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ServerInfo constructServerInfo(String name, InetSocketAddress address, boolean restricted)
|
public ServerInfo constructServerInfo(String name, InetSocketAddress address, String motd, boolean restricted)
|
||||||
{
|
{
|
||||||
return new BungeeServerInfo( name, address, restricted );
|
return new BungeeServerInfo( name, address, motd, restricted );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -487,7 +498,9 @@ public class BungeeCord extends ProxyServer
|
|||||||
public void broadcast(String message)
|
public void broadcast(String message)
|
||||||
{
|
{
|
||||||
getConsole().sendMessage( message );
|
getConsole().sendMessage( message );
|
||||||
broadcast( new Packet3Chat( message ) );
|
// TODO: Here too
|
||||||
|
String encoded = BungeeCord.getInstance().gson.toJson( message );
|
||||||
|
broadcast( new Packet3Chat( "{\"text\":" + encoded + "}" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addConnection(UserConnection con)
|
public void addConnection(UserConnection con)
|
||||||
@@ -519,4 +532,9 @@ public class BungeeCord extends ProxyServer
|
|||||||
{
|
{
|
||||||
return new Custom( player );
|
return new Custom( player );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<String> getDisabledCommands()
|
||||||
|
{
|
||||||
|
return config.getDisabledCommands();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -38,6 +38,8 @@ public class BungeeServerInfo implements ServerInfo
|
|||||||
private final InetSocketAddress address;
|
private final InetSocketAddress address;
|
||||||
private final Collection<ProxiedPlayer> players = new ArrayList<>();
|
private final Collection<ProxiedPlayer> players = new ArrayList<>();
|
||||||
@Getter
|
@Getter
|
||||||
|
private final String motd;
|
||||||
|
@Getter
|
||||||
private final boolean restricted;
|
private final boolean restricted;
|
||||||
@Getter
|
@Getter
|
||||||
private final Queue<DefinedPacket> packetQueue = new LinkedList<>();
|
private final Queue<DefinedPacket> packetQueue = new LinkedList<>();
|
||||||
|
27
proxy/src/main/java/net/md_5/bungee/ConnectionThrottle.java
Normal file
27
proxy/src/main/java/net/md_5/bungee/ConnectionThrottle.java
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package net.md_5.bungee;
|
||||||
|
|
||||||
|
import gnu.trove.map.hash.TObjectLongHashMap;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ConnectionThrottle
|
||||||
|
{
|
||||||
|
|
||||||
|
private final TObjectLongHashMap<InetAddress> throttle = new TObjectLongHashMap<>();
|
||||||
|
private final int throttleTime;
|
||||||
|
|
||||||
|
public void unthrottle(InetAddress address)
|
||||||
|
{
|
||||||
|
throttle.remove( address );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean throttle(InetAddress address)
|
||||||
|
{
|
||||||
|
long value = throttle.get( address );
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
throttle.put( address, currentTime );
|
||||||
|
return value != 0 && currentTime - value < throttleTime;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,7 @@
|
|||||||
package net.md_5.bungee;
|
package net.md_5.bungee;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to rewrite integers within packets.
|
* Class to rewrite integers within packets.
|
||||||
*/
|
*/
|
||||||
@@ -102,6 +104,10 @@ public class EntityMap
|
|||||||
{
|
{
|
||||||
1
|
1
|
||||||
};
|
};
|
||||||
|
entityIds[0x2C] = new int[]
|
||||||
|
{
|
||||||
|
1
|
||||||
|
};
|
||||||
entityIds[0x37] = new int[]
|
entityIds[0x37] = new int[]
|
||||||
{
|
{
|
||||||
1
|
1
|
||||||
@@ -113,20 +119,20 @@ public class EntityMap
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void rewrite(byte[] packet, int oldId, int newId)
|
public static void rewrite(ByteBuf packet, int oldId, int newId)
|
||||||
{
|
{
|
||||||
int packetId = packet[0] & 0xFF;
|
int packetId = packet.getUnsignedByte( 0 );
|
||||||
if ( packetId == 0x1D )
|
if ( packetId == 0x1D )
|
||||||
{ // bulk entity
|
{ // bulk entity
|
||||||
for ( int pos = 2; pos < packet.length; pos += 4 )
|
for ( int pos = 2; pos < packet.readableBytes(); pos += 4 )
|
||||||
{
|
{
|
||||||
int readId = readInt( packet, pos );
|
int readId = packet.getInt( pos );
|
||||||
if ( readId == oldId )
|
if ( readId == oldId )
|
||||||
{
|
{
|
||||||
setInt( packet, pos, newId );
|
packet.setInt( pos, newId );
|
||||||
} else if ( readId == newId )
|
} else if ( readId == newId )
|
||||||
{
|
{
|
||||||
setInt( packet, pos, oldId );
|
packet.setInt( pos, oldId );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
@@ -136,41 +142,28 @@ public class EntityMap
|
|||||||
{
|
{
|
||||||
for ( int pos : idArray )
|
for ( int pos : idArray )
|
||||||
{
|
{
|
||||||
int readId = readInt( packet, pos );
|
int readId = packet.getInt( pos );
|
||||||
if ( readId == oldId )
|
if ( readId == oldId )
|
||||||
{
|
{
|
||||||
setInt( packet, pos, newId );
|
packet.setInt( pos, newId );
|
||||||
} else if ( readId == newId )
|
} else if ( readId == newId )
|
||||||
{
|
{
|
||||||
setInt( packet, pos, oldId );
|
packet.setInt( pos, oldId );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( packetId == 0x17 )
|
if ( packetId == 0x17 )
|
||||||
{
|
{
|
||||||
int type = packet[5] & 0xFF;
|
int type = packet.getUnsignedByte( 5 );
|
||||||
if ( type == 60 || type == 90 )
|
if ( type == 60 || type == 90 )
|
||||||
{
|
{
|
||||||
int index20 = readInt( packet, 20 );
|
int index20 = packet.getInt( 20 );
|
||||||
if ( packet.length > 24 && index20 == oldId )
|
if ( packet.readableBytes() > 24 && index20 == oldId )
|
||||||
{
|
{
|
||||||
setInt( packet, 20, newId );
|
packet.setInt( 20, newId );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setInt(byte[] buf, int pos, int i)
|
|
||||||
{
|
|
||||||
buf[pos] = (byte) ( i >> 24 );
|
|
||||||
buf[pos + 1] = (byte) ( i >> 16 );
|
|
||||||
buf[pos + 2] = (byte) ( i >> 8 );
|
|
||||||
buf[pos + 3] = (byte) i;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -42,6 +42,7 @@ public class ServerConnection implements Server
|
|||||||
{
|
{
|
||||||
if ( !ch.isClosed() )
|
if ( !ch.isClosed() )
|
||||||
{
|
{
|
||||||
|
// TODO: Can we just use a future here?
|
||||||
unsafe().sendPacket( new PacketFFKick( reason ) );
|
unsafe().sendPacket( new PacketFFKick( reason ) );
|
||||||
ch.getHandle().eventLoop().schedule( new Runnable()
|
ch.getHandle().eventLoop().schedule( new Runnable()
|
||||||
{
|
{
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
package net.md_5.bungee;
|
package net.md_5.bungee;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.io.ByteArrayDataInput;
|
|
||||||
import com.google.common.io.ByteArrayDataOutput;
|
import com.google.common.io.ByteArrayDataOutput;
|
||||||
import com.google.common.io.ByteStreams;
|
import com.google.common.io.ByteStreams;
|
||||||
|
import java.io.DataInput;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
@@ -29,6 +29,7 @@ import net.md_5.bungee.netty.PacketDecoder;
|
|||||||
import net.md_5.bungee.netty.PacketHandler;
|
import net.md_5.bungee.netty.PacketHandler;
|
||||||
import net.md_5.bungee.netty.PipelineUtils;
|
import net.md_5.bungee.netty.PipelineUtils;
|
||||||
import net.md_5.bungee.protocol.Forge;
|
import net.md_5.bungee.protocol.Forge;
|
||||||
|
import net.md_5.bungee.protocol.MinecraftOutput;
|
||||||
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
||||||
import net.md_5.bungee.protocol.packet.Packet1Login;
|
import net.md_5.bungee.protocol.packet.Packet1Login;
|
||||||
import net.md_5.bungee.protocol.packet.Packet9Respawn;
|
import net.md_5.bungee.protocol.packet.Packet9Respawn;
|
||||||
@@ -153,6 +154,10 @@ public class ServerConnector extends PacketHandler
|
|||||||
(byte) user.getPendingConnection().getListener().getTabListSize() );
|
(byte) user.getPendingConnection().getListener().getTabListSize() );
|
||||||
}
|
}
|
||||||
user.unsafe().sendPacket( modLogin );
|
user.unsafe().sendPacket( modLogin );
|
||||||
|
|
||||||
|
MinecraftOutput out = new MinecraftOutput();
|
||||||
|
out.writeStringUTF8WithoutLengthHeaderBecauseDinnerboneStuffedUpTheMCBrandPacket( ProxyServer.getInstance().getName() + " (" + ProxyServer.getInstance().getVersion() + ")" );
|
||||||
|
user.unsafe().sendPacket( new PacketFAPluginMessage( "MC|Brand", out.toArray() ) );
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
user.getTabList().onServerChange();
|
user.getTabList().onServerChange();
|
||||||
@@ -220,7 +225,7 @@ public class ServerConnector extends PacketHandler
|
|||||||
ch.write( new PacketFCEncryptionResponse( shared, token ) );
|
ch.write( new PacketFCEncryptionResponse( shared, token ) );
|
||||||
|
|
||||||
Cipher encrypt = EncryptionUtil.getCipher( Cipher.ENCRYPT_MODE, secretkey );
|
Cipher encrypt = EncryptionUtil.getCipher( Cipher.ENCRYPT_MODE, secretkey );
|
||||||
ch.getHandle().pipeline().addBefore( PipelineUtils.PACKET_DECODE_HANDLER, PipelineUtils.ENCRYPT_HANDLER, new CipherEncoder( encrypt ) );
|
ch.addBefore( PipelineUtils.PACKET_DECODE_HANDLER, PipelineUtils.ENCRYPT_HANDLER, new CipherEncoder( encrypt ) );
|
||||||
|
|
||||||
thisState = State.ENCRYPT_RESPONSE;
|
thisState = State.ENCRYPT_RESPONSE;
|
||||||
} else
|
} else
|
||||||
@@ -235,7 +240,7 @@ public class ServerConnector extends PacketHandler
|
|||||||
Preconditions.checkState( thisState == State.ENCRYPT_RESPONSE, "Not expecting ENCRYPT_RESPONSE" );
|
Preconditions.checkState( thisState == State.ENCRYPT_RESPONSE, "Not expecting ENCRYPT_RESPONSE" );
|
||||||
|
|
||||||
Cipher decrypt = EncryptionUtil.getCipher( Cipher.DECRYPT_MODE, secretkey );
|
Cipher decrypt = EncryptionUtil.getCipher( Cipher.DECRYPT_MODE, secretkey );
|
||||||
ch.getHandle().pipeline().addBefore( PipelineUtils.PACKET_DECODE_HANDLER, PipelineUtils.DECRYPT_HANDLER, new CipherDecoder( decrypt ) );
|
ch.addBefore( PipelineUtils.PACKET_DECODE_HANDLER, PipelineUtils.DECRYPT_HANDLER, new CipherDecoder( decrypt ) );
|
||||||
|
|
||||||
ch.write( user.getPendingConnection().getForgeLogin() );
|
ch.write( user.getPendingConnection().getForgeLogin() );
|
||||||
|
|
||||||
@@ -251,14 +256,14 @@ public class ServerConnector extends PacketHandler
|
|||||||
{
|
{
|
||||||
def = null;
|
def = null;
|
||||||
}
|
}
|
||||||
ServerKickEvent event = bungee.getPluginManager().callEvent( new ServerKickEvent( user, kick.getMessage(), def ) );
|
ServerKickEvent event = bungee.getPluginManager().callEvent( new ServerKickEvent( user, kick.getMessage(), def, ServerKickEvent.State.CONNECTING ) );
|
||||||
if ( event.isCancelled() && event.getCancelServer() != null )
|
if ( event.isCancelled() && event.getCancelServer() != null )
|
||||||
{
|
{
|
||||||
user.connect( event.getCancelServer() );
|
user.connect( event.getCancelServer() );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String message = bungee.getTranslation( "connect_kick" ) + target.getName() + ": " + kick.getMessage();
|
String message = bungee.getTranslation( "connect_kick" ) + target.getName() + ": " + event.getKickReason();
|
||||||
if ( user.getServer() == null )
|
if ( user.getServer() == null )
|
||||||
{
|
{
|
||||||
user.disconnect( message );
|
user.disconnect( message );
|
||||||
@@ -276,10 +281,9 @@ public class ServerConnector extends PacketHandler
|
|||||||
throw new IllegalStateException( "May not connect to another BungeCord!" );
|
throw new IllegalStateException( "May not connect to another BungeCord!" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( pluginMessage.getTag().equals( "FML" ) && ( pluginMessage.getData()[0] & 0xFF ) == 0 )
|
DataInput in = pluginMessage.getStream();
|
||||||
|
if ( pluginMessage.getTag().equals( "FML" ) && in.readUnsignedByte() == 0 )
|
||||||
{
|
{
|
||||||
ByteArrayDataInput in = ByteStreams.newDataInput( pluginMessage.getData() );
|
|
||||||
in.readUnsignedByte();
|
|
||||||
int count = in.readInt();
|
int count = in.readInt();
|
||||||
for ( int i = 0; i < count; i++ )
|
for ( int i = 0; i < count; i++ )
|
||||||
{
|
{
|
||||||
|
@@ -22,7 +22,6 @@ import lombok.Setter;
|
|||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.config.ServerInfo;
|
import net.md_5.bungee.api.config.ServerInfo;
|
||||||
import net.md_5.bungee.api.config.TexturePackInfo;
|
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
import net.md_5.bungee.api.event.PermissionCheckEvent;
|
import net.md_5.bungee.api.event.PermissionCheckEvent;
|
||||||
import net.md_5.bungee.api.event.ServerConnectEvent;
|
import net.md_5.bungee.api.event.ServerConnectEvent;
|
||||||
@@ -31,6 +30,7 @@ import net.md_5.bungee.api.tab.TabListHandler;
|
|||||||
import net.md_5.bungee.connection.InitialHandler;
|
import net.md_5.bungee.connection.InitialHandler;
|
||||||
import net.md_5.bungee.netty.ChannelWrapper;
|
import net.md_5.bungee.netty.ChannelWrapper;
|
||||||
import net.md_5.bungee.netty.HandlerBoss;
|
import net.md_5.bungee.netty.HandlerBoss;
|
||||||
|
import net.md_5.bungee.netty.PacketWrapper;
|
||||||
import net.md_5.bungee.netty.PipelineUtils;
|
import net.md_5.bungee.netty.PipelineUtils;
|
||||||
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
||||||
import net.md_5.bungee.protocol.packet.Packet3Chat;
|
import net.md_5.bungee.protocol.packet.Packet3Chat;
|
||||||
@@ -73,6 +73,9 @@ public final class UserConnection implements ProxiedPlayer
|
|||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
private int ping = 100;
|
private int ping = 100;
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private ServerInfo reconnectServer;
|
||||||
/*========================================================================*/
|
/*========================================================================*/
|
||||||
private final Collection<String> groups = new CaseInsensitiveSet();
|
private final Collection<String> groups = new CaseInsensitiveSet();
|
||||||
private final Collection<String> permissions = new CaseInsensitiveSet();
|
private final Collection<String> permissions = new CaseInsensitiveSet();
|
||||||
@@ -127,9 +130,9 @@ public final class UserConnection implements ProxiedPlayer
|
|||||||
this.tabList = tabList;
|
this.tabList = tabList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendPacket(byte[] b)
|
public void sendPacket(PacketWrapper packet)
|
||||||
{
|
{
|
||||||
ch.write( b );
|
ch.write( packet );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@@ -178,12 +181,12 @@ public final class UserConnection implements ProxiedPlayer
|
|||||||
|
|
||||||
if ( getServer() != null && Objects.equals( getServer().getInfo(), target ) )
|
if ( getServer() != null && Objects.equals( getServer().getInfo(), target ) )
|
||||||
{
|
{
|
||||||
sendMessage( ChatColor.RED + "Cannot connect to server you are already on!" );
|
sendMessage( bungee.getTranslation( "already_connected" ) );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ( pendingConnects.contains( target ) )
|
if ( pendingConnects.contains( target ) )
|
||||||
{
|
{
|
||||||
sendMessage( ChatColor.RED + "Already connecting to this server!" );
|
sendMessage( bungee.getTranslation( "already_connecting" ) );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,7 +212,7 @@ public final class UserConnection implements ProxiedPlayer
|
|||||||
pendingConnects.remove( target );
|
pendingConnects.remove( target );
|
||||||
|
|
||||||
ServerInfo def = ProxyServer.getInstance().getServers().get( getPendingConnection().getListener().getFallbackServer() );
|
ServerInfo def = ProxyServer.getInstance().getServers().get( getPendingConnection().getListener().getFallbackServer() );
|
||||||
if ( retry & target != def && ( getServer() == null || def != getServer().getInfo() ) )
|
if ( retry && target != def && ( getServer() == null || def != getServer().getInfo() ) )
|
||||||
{
|
{
|
||||||
sendMessage( bungee.getTranslation( "fallback_lobby" ) );
|
sendMessage( bungee.getTranslation( "fallback_lobby" ) );
|
||||||
connect( def, false );
|
connect( def, false );
|
||||||
@@ -233,7 +236,7 @@ public final class UserConnection implements ProxiedPlayer
|
|||||||
.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000 ) // TODO: Configurable
|
.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000 ) // TODO: Configurable
|
||||||
.remoteAddress( target.getAddress() );
|
.remoteAddress( target.getAddress() );
|
||||||
// Windows is bugged, multi homed users will just have to live with random connecting IPs
|
// Windows is bugged, multi homed users will just have to live with random connecting IPs
|
||||||
if ( !PlatformDependent.isWindows() )
|
if ( getPendingConnection().getListener().isSetLocalAddress() && !PlatformDependent.isWindows() )
|
||||||
{
|
{
|
||||||
b.localAddress( getPendingConnection().getListener().getHost().getHostString(), 0 );
|
b.localAddress( getPendingConnection().getListener().getHost().getHostString(), 0 );
|
||||||
}
|
}
|
||||||
@@ -265,7 +268,9 @@ public final class UserConnection implements ProxiedPlayer
|
|||||||
@Override
|
@Override
|
||||||
public void sendMessage(String message)
|
public void sendMessage(String message)
|
||||||
{
|
{
|
||||||
unsafe().sendPacket( new Packet3Chat( message ) );
|
// TODO: Fix this
|
||||||
|
String encoded = BungeeCord.getInstance().gson.toJson( message );
|
||||||
|
unsafe().sendPacket( new Packet3Chat( "{\"text\":" + encoded + "}" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -345,12 +350,6 @@ public final class UserConnection implements ProxiedPlayer
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setTexturePack(TexturePackInfo pack)
|
|
||||||
{
|
|
||||||
unsafe().sendPacket( new PacketFAPluginMessage( "MC|TPack", ( pack.getUrl() + "\00" + pack.getSize() ).getBytes() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Unsafe unsafe()
|
public Unsafe unsafe()
|
||||||
{
|
{
|
||||||
|
@@ -41,7 +41,6 @@ public class CommandAlert extends Command
|
|||||||
String message = builder.substring( 0, builder.length() - 1 );
|
String message = builder.substring( 0, builder.length() - 1 );
|
||||||
|
|
||||||
ProxyServer.getInstance().broadcast( message );
|
ProxyServer.getInstance().broadcast( message );
|
||||||
ProxyServer.getInstance().getConsole().sendMessage( message );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,12 +1,12 @@
|
|||||||
package net.md_5.bungee.command;
|
package net.md_5.bungee.command;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.CommandSender;
|
import net.md_5.bungee.api.CommandSender;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
import net.md_5.bungee.api.plugin.Command;
|
|
||||||
|
|
||||||
public class CommandFind extends Command
|
public class CommandFind extends PlayerCommand
|
||||||
{
|
{
|
||||||
|
|
||||||
public CommandFind()
|
public CommandFind()
|
||||||
@@ -32,4 +32,10 @@ public class CommandFind extends Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterable<String> onTabComplete(CommandSender sender, String[] args)
|
||||||
|
{
|
||||||
|
return ( args.length == 0 ) ? super.onTabComplete( sender, args ) : Collections.EMPTY_LIST;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,7 @@ package net.md_5.bungee.command;
|
|||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import net.md_5.bungee.Util;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.CommandSender;
|
import net.md_5.bungee.api.CommandSender;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
@@ -18,15 +19,12 @@ public class CommandPerms extends Command
|
|||||||
@Override
|
@Override
|
||||||
public void execute(CommandSender sender, String[] args)
|
public void execute(CommandSender sender, String[] args)
|
||||||
{
|
{
|
||||||
StringBuilder groups = new StringBuilder();
|
|
||||||
Set<String> permissions = new HashSet<>();
|
Set<String> permissions = new HashSet<>();
|
||||||
for ( String group : sender.getGroups() )
|
for ( String group : sender.getGroups() )
|
||||||
{
|
{
|
||||||
groups.append( group );
|
|
||||||
groups.append( ", " );
|
|
||||||
permissions.addAll( ProxyServer.getInstance().getConfigurationAdapter().getPermissions( group ) );
|
permissions.addAll( ProxyServer.getInstance().getConfigurationAdapter().getPermissions( group ) );
|
||||||
}
|
}
|
||||||
sender.sendMessage( ChatColor.GOLD + "You have the following groups: " + groups.substring( 0, groups.length() - 2 ) );
|
sender.sendMessage( ChatColor.GOLD + "You have the following groups: " + Util.csv( sender.getGroups() ) );
|
||||||
|
|
||||||
for ( String permission : permissions )
|
for ( String permission : permissions )
|
||||||
{
|
{
|
||||||
|
@@ -1,16 +1,21 @@
|
|||||||
package net.md_5.bungee.command;
|
package net.md_5.bungee.command;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import net.md_5.bungee.api.CommandSender;
|
import net.md_5.bungee.api.CommandSender;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.config.ServerInfo;
|
import net.md_5.bungee.api.config.ServerInfo;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
import net.md_5.bungee.api.plugin.Command;
|
import net.md_5.bungee.api.plugin.Command;
|
||||||
|
import net.md_5.bungee.api.plugin.TabExecutor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 implements TabExecutor
|
||||||
{
|
{
|
||||||
|
|
||||||
public CommandServer()
|
public CommandServer()
|
||||||
@@ -60,4 +65,24 @@ public class CommandServer extends Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterable<String> onTabComplete(final CommandSender sender, String[] args)
|
||||||
|
{
|
||||||
|
return ( args.length != 0 ) ? Collections.EMPTY_LIST : Iterables.transform( Iterables.filter( ProxyServer.getInstance().getServers().values(), new Predicate<ServerInfo>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean apply(ServerInfo input)
|
||||||
|
{
|
||||||
|
return input.canAccess( sender );
|
||||||
|
}
|
||||||
|
} ), new Function<ServerInfo, String>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public String apply(ServerInfo input)
|
||||||
|
{
|
||||||
|
return input.getName();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,36 @@
|
|||||||
|
package net.md_5.bungee.command;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import net.md_5.bungee.api.CommandSender;
|
||||||
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
import net.md_5.bungee.api.plugin.Command;
|
||||||
|
import net.md_5.bungee.api.plugin.TabExecutor;
|
||||||
|
|
||||||
|
public abstract class PlayerCommand extends Command implements TabExecutor
|
||||||
|
{
|
||||||
|
|
||||||
|
public PlayerCommand(String name)
|
||||||
|
{
|
||||||
|
super( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerCommand(String name, String permission, String... aliases)
|
||||||
|
{
|
||||||
|
super( name, permission, aliases );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterable<String> onTabComplete(CommandSender sender, String[] args)
|
||||||
|
{
|
||||||
|
return Iterables.transform( ProxyServer.getInstance().getPlayers(), new Function<ProxiedPlayer, String>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public String apply(ProxiedPlayer input)
|
||||||
|
{
|
||||||
|
return input.getDisplayName();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
@@ -2,6 +2,7 @@ package net.md_5.bungee.config;
|
|||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import gnu.trove.map.TMap;
|
import gnu.trove.map.TMap;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -10,10 +11,8 @@ import net.md_5.bungee.api.ProxyServer;
|
|||||||
import net.md_5.bungee.api.config.ConfigurationAdapter;
|
import net.md_5.bungee.api.config.ConfigurationAdapter;
|
||||||
import net.md_5.bungee.api.config.ListenerInfo;
|
import net.md_5.bungee.api.config.ListenerInfo;
|
||||||
import net.md_5.bungee.api.config.ServerInfo;
|
import net.md_5.bungee.api.config.ServerInfo;
|
||||||
import net.md_5.bungee.tab.GlobalPing;
|
|
||||||
import net.md_5.bungee.tab.Global;
|
|
||||||
import net.md_5.bungee.tab.ServerUnique;
|
|
||||||
import net.md_5.bungee.util.CaseInsensitiveMap;
|
import net.md_5.bungee.util.CaseInsensitiveMap;
|
||||||
|
import net.md_5.bungee.util.CaseInsensitiveSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Core configuration for the proxy.
|
* Core configuration for the proxy.
|
||||||
@@ -43,6 +42,8 @@ public class Configuration
|
|||||||
*/
|
*/
|
||||||
private boolean onlineMode = true;
|
private boolean onlineMode = true;
|
||||||
private int playerLimit = -1;
|
private int playerLimit = -1;
|
||||||
|
private Collection<String> disabledCommands;
|
||||||
|
private int throttle = 4000;
|
||||||
|
|
||||||
public void load()
|
public void load()
|
||||||
{
|
{
|
||||||
@@ -54,6 +55,9 @@ public class Configuration
|
|||||||
uuid = adapter.getString( "stats", uuid );
|
uuid = adapter.getString( "stats", uuid );
|
||||||
onlineMode = adapter.getBoolean( "online_mode", onlineMode );
|
onlineMode = adapter.getBoolean( "online_mode", onlineMode );
|
||||||
playerLimit = adapter.getInt( "player_limit", playerLimit );
|
playerLimit = adapter.getInt( "player_limit", playerLimit );
|
||||||
|
throttle = adapter.getInt( "connection_throttle", throttle );
|
||||||
|
|
||||||
|
disabledCommands = new CaseInsensitiveSet( (Collection<String>) adapter.getList( "disabled_commands", Arrays.asList( "find" ) ) );
|
||||||
|
|
||||||
Preconditions.checkArgument( listeners != null && !listeners.isEmpty(), "No listeners defined." );
|
Preconditions.checkArgument( listeners != null && !listeners.isEmpty(), "No listeners defined." );
|
||||||
|
|
||||||
@@ -84,6 +88,7 @@ public class Configuration
|
|||||||
for ( ListenerInfo listener : listeners )
|
for ( ListenerInfo listener : listeners )
|
||||||
{
|
{
|
||||||
Preconditions.checkArgument( servers.containsKey( listener.getDefaultServer() ), "Default server %s is not defined", listener.getDefaultServer() );
|
Preconditions.checkArgument( servers.containsKey( listener.getDefaultServer() ), "Default server %s is not defined", listener.getDefaultServer() );
|
||||||
|
Preconditions.checkArgument( servers.containsKey( listener.getFallbackServer() ), "Fallback server %s is not defined", listener.getFallbackServer() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -21,7 +21,6 @@ import net.md_5.bungee.api.ProxyServer;
|
|||||||
import net.md_5.bungee.api.config.ConfigurationAdapter;
|
import net.md_5.bungee.api.config.ConfigurationAdapter;
|
||||||
import net.md_5.bungee.api.config.ListenerInfo;
|
import net.md_5.bungee.api.config.ListenerInfo;
|
||||||
import net.md_5.bungee.api.config.ServerInfo;
|
import net.md_5.bungee.api.config.ServerInfo;
|
||||||
import net.md_5.bungee.api.config.TexturePackInfo;
|
|
||||||
import net.md_5.bungee.api.tab.TabListHandler;
|
import net.md_5.bungee.api.tab.TabListHandler;
|
||||||
import net.md_5.bungee.tab.Global;
|
import net.md_5.bungee.tab.Global;
|
||||||
import net.md_5.bungee.tab.GlobalPing;
|
import net.md_5.bungee.tab.GlobalPing;
|
||||||
@@ -171,9 +170,10 @@ public class YamlConfig implements ConfigurationAdapter
|
|||||||
Map<String, Object> val = entry.getValue();
|
Map<String, Object> val = entry.getValue();
|
||||||
String name = entry.getKey();
|
String name = entry.getKey();
|
||||||
String addr = get( "address", "localhost:25565", val );
|
String addr = get( "address", "localhost:25565", val );
|
||||||
|
String motd = ChatColor.translateAlternateColorCodes( '&', get( "motd", "&1Just another BungeeCord - Forced Host", val ) );
|
||||||
boolean restricted = get( "restricted", false, val );
|
boolean restricted = get( "restricted", false, val );
|
||||||
InetSocketAddress address = Util.getAddr( addr );
|
InetSocketAddress address = Util.getAddr( addr );
|
||||||
ServerInfo info = ProxyServer.getInstance().constructServerInfo( name, address, restricted );
|
ServerInfo info = ProxyServer.getInstance().constructServerInfo( name, address, motd, restricted );
|
||||||
ret.put( name, info );
|
ret.put( name, info );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +195,7 @@ public class YamlConfig implements ConfigurationAdapter
|
|||||||
|
|
||||||
for ( Map<String, Object> val : base )
|
for ( Map<String, Object> val : base )
|
||||||
{
|
{
|
||||||
String motd = get( "motd", "Another Bungee server", val );
|
String motd = get( "motd", "&1Another Bungee server", val );
|
||||||
motd = ChatColor.translateAlternateColorCodes( '&', motd );
|
motd = ChatColor.translateAlternateColorCodes( '&', motd );
|
||||||
|
|
||||||
int maxPlayers = get( "max_players", 1, val );
|
int maxPlayers = get( "max_players", 1, val );
|
||||||
@@ -206,17 +206,16 @@ public class YamlConfig implements ConfigurationAdapter
|
|||||||
int tabListSize = get( "tab_size", 60, val );
|
int tabListSize = get( "tab_size", 60, val );
|
||||||
InetSocketAddress address = Util.getAddr( host );
|
InetSocketAddress address = Util.getAddr( host );
|
||||||
Map<String, String> forced = new CaseInsensitiveMap<>( get( "forced_hosts", forcedDef, val ) );
|
Map<String, String> forced = new CaseInsensitiveMap<>( get( "forced_hosts", forcedDef, val ) );
|
||||||
String textureURL = get( "texture_url", null, val );
|
|
||||||
int textureSize = get( "texture_size", 16, val );
|
|
||||||
TexturePackInfo texture = ( textureURL == null ) ? null : new TexturePackInfo( textureURL, textureSize );
|
|
||||||
String tabListName = get( "tab_list", "GLOBAL_PING", val );
|
String tabListName = get( "tab_list", "GLOBAL_PING", val );
|
||||||
DefaultTabList value = DefaultTabList.valueOf( tabListName.toUpperCase() );
|
DefaultTabList value = DefaultTabList.valueOf( tabListName.toUpperCase() );
|
||||||
if ( value == null )
|
if ( value == null )
|
||||||
{
|
{
|
||||||
value = DefaultTabList.GLOBAL_PING;
|
value = DefaultTabList.GLOBAL_PING;
|
||||||
}
|
}
|
||||||
|
boolean setLocalAddress = get( "bind_local_address", true, val );
|
||||||
|
boolean pingPassthrough = get( "ping_passthrough", false, val );
|
||||||
|
|
||||||
ListenerInfo info = new ListenerInfo( address, motd, maxPlayers, tabListSize, defaultServer, fallbackServer, forceDefault, forced, texture, value.clazz );
|
ListenerInfo info = new ListenerInfo( address, motd, maxPlayers, tabListSize, defaultServer, fallbackServer, forceDefault, forced, value.clazz, setLocalAddress, pingPassthrough );
|
||||||
ret.add( info );
|
ret.add( info );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,6 +232,12 @@ public class YamlConfig implements ConfigurationAdapter
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<?> getList(String path, Collection<?> def)
|
||||||
|
{
|
||||||
|
return get( path, def );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public Collection<String> getPermissions(String group)
|
public Collection<String> getPermissions(String group)
|
||||||
|
@@ -1,15 +1,14 @@
|
|||||||
package net.md_5.bungee.connection;
|
package net.md_5.bungee.connection;
|
||||||
|
|
||||||
import com.google.common.io.ByteArrayDataInput;
|
|
||||||
import com.google.common.io.ByteArrayDataOutput;
|
import com.google.common.io.ByteArrayDataOutput;
|
||||||
import com.google.common.io.ByteStreams;
|
import com.google.common.io.ByteStreams;
|
||||||
|
import java.io.DataInput;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import net.md_5.bungee.EntityMap;
|
import net.md_5.bungee.EntityMap;
|
||||||
import net.md_5.bungee.ServerConnection;
|
import net.md_5.bungee.ServerConnection;
|
||||||
import net.md_5.bungee.UserConnection;
|
import net.md_5.bungee.UserConnection;
|
||||||
import net.md_5.bungee.Util;
|
import net.md_5.bungee.Util;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.config.ServerInfo;
|
import net.md_5.bungee.api.config.ServerInfo;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
@@ -22,6 +21,7 @@ import net.md_5.bungee.api.score.Scoreboard;
|
|||||||
import net.md_5.bungee.api.score.Team;
|
import net.md_5.bungee.api.score.Team;
|
||||||
import net.md_5.bungee.netty.ChannelWrapper;
|
import net.md_5.bungee.netty.ChannelWrapper;
|
||||||
import net.md_5.bungee.netty.PacketHandler;
|
import net.md_5.bungee.netty.PacketHandler;
|
||||||
|
import net.md_5.bungee.netty.PacketWrapper;
|
||||||
import net.md_5.bungee.protocol.packet.Packet0KeepAlive;
|
import net.md_5.bungee.protocol.packet.Packet0KeepAlive;
|
||||||
import net.md_5.bungee.protocol.packet.PacketC9PlayerListItem;
|
import net.md_5.bungee.protocol.packet.PacketC9PlayerListItem;
|
||||||
import net.md_5.bungee.protocol.packet.PacketCEScoreboardObjective;
|
import net.md_5.bungee.protocol.packet.PacketCEScoreboardObjective;
|
||||||
@@ -31,8 +31,6 @@ import net.md_5.bungee.protocol.packet.PacketD1Team;
|
|||||||
import net.md_5.bungee.protocol.packet.PacketFAPluginMessage;
|
import net.md_5.bungee.protocol.packet.PacketFAPluginMessage;
|
||||||
import net.md_5.bungee.protocol.packet.PacketFFKick;
|
import net.md_5.bungee.protocol.packet.PacketFFKick;
|
||||||
|
|
||||||
;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class DownstreamBridge extends PacketHandler
|
public class DownstreamBridge extends PacketHandler
|
||||||
{
|
{
|
||||||
@@ -47,8 +45,9 @@ public class DownstreamBridge extends PacketHandler
|
|||||||
ServerInfo def = bungee.getServerInfo( con.getPendingConnection().getListener().getFallbackServer() );
|
ServerInfo def = bungee.getServerInfo( con.getPendingConnection().getListener().getFallbackServer() );
|
||||||
if ( server.getInfo() != def )
|
if ( server.getInfo() != def )
|
||||||
{
|
{
|
||||||
|
server.setObsolete( true );
|
||||||
con.connectNow( def );
|
con.connectNow( def );
|
||||||
con.sendMessage( ChatColor.RED + "The server you were previously on went down, you have been connected to the lobby" );
|
con.sendMessage( bungee.getTranslation( "server_went_down" ) );
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
con.disconnect( Util.exception( t ) );
|
con.disconnect( Util.exception( t ) );
|
||||||
@@ -60,7 +59,10 @@ public class DownstreamBridge extends PacketHandler
|
|||||||
{
|
{
|
||||||
// We lost connection to the server
|
// We lost connection to the server
|
||||||
server.getInfo().removePlayer( con );
|
server.getInfo().removePlayer( con );
|
||||||
|
if ( bungee.getReconnectHandler() != null )
|
||||||
|
{
|
||||||
bungee.getReconnectHandler().setServer( con );
|
bungee.getReconnectHandler().setServer( con );
|
||||||
|
}
|
||||||
|
|
||||||
if ( !server.isObsolete() )
|
if ( !server.isObsolete() )
|
||||||
{
|
{
|
||||||
@@ -69,12 +71,12 @@ public class DownstreamBridge extends PacketHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(byte[] buf) throws Exception
|
public void handle(PacketWrapper packet) throws Exception
|
||||||
{
|
{
|
||||||
if ( !server.isObsolete() )
|
if ( !server.isObsolete() )
|
||||||
{
|
{
|
||||||
EntityMap.rewrite( buf, con.getServerEntityId(), con.getClientEntityId() );
|
EntityMap.rewrite( packet.buf, con.getServerEntityId(), con.getClientEntityId() );
|
||||||
con.sendPacket( buf );
|
con.sendPacket( packet );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,7 +187,7 @@ public class DownstreamBridge extends PacketHandler
|
|||||||
@Override
|
@Override
|
||||||
public void handle(PacketFAPluginMessage pluginMessage) throws Exception
|
public void handle(PacketFAPluginMessage pluginMessage) throws Exception
|
||||||
{
|
{
|
||||||
ByteArrayDataInput in = ByteStreams.newDataInput( pluginMessage.getData() );
|
DataInput in = pluginMessage.getStream();
|
||||||
PluginMessageEvent event = new PluginMessageEvent( con.getServer(), con, pluginMessage.getTag(), pluginMessage.getData().clone() );
|
PluginMessageEvent event = new PluginMessageEvent( con.getServer(), con, pluginMessage.getTag(), pluginMessage.getData().clone() );
|
||||||
|
|
||||||
if ( bungee.getPluginManager().callEvent( event ).isCancelled() )
|
if ( bungee.getPluginManager().callEvent( event ).isCancelled() )
|
||||||
@@ -193,11 +195,6 @@ public class DownstreamBridge extends PacketHandler
|
|||||||
throw new CancelSendSignal();
|
throw new CancelSendSignal();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( pluginMessage.getTag().equals( "MC|TPack" ) && con.getPendingConnection().getListener().getTexturePack() != null )
|
|
||||||
{
|
|
||||||
throw new CancelSendSignal();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( pluginMessage.getTag().equals( "BungeeCord" ) )
|
if ( pluginMessage.getTag().equals( "BungeeCord" ) )
|
||||||
{
|
{
|
||||||
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
||||||
@@ -247,6 +244,18 @@ public class DownstreamBridge extends PacketHandler
|
|||||||
con.connect( server );
|
con.connect( server );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ( subChannel.equals( "ConnectOther" ) )
|
||||||
|
{
|
||||||
|
ProxiedPlayer player = bungee.getPlayer( in.readUTF() );
|
||||||
|
if ( player != null )
|
||||||
|
{
|
||||||
|
ServerInfo server = bungee.getServerInfo( in.readUTF() );
|
||||||
|
if ( server != null )
|
||||||
|
{
|
||||||
|
player.connect( server );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if ( subChannel.equals( "IP" ) )
|
if ( subChannel.equals( "IP" ) )
|
||||||
{
|
{
|
||||||
out.writeUTF( "IP" );
|
out.writeUTF( "IP" );
|
||||||
@@ -328,7 +337,7 @@ public class DownstreamBridge extends PacketHandler
|
|||||||
{
|
{
|
||||||
def = null;
|
def = null;
|
||||||
}
|
}
|
||||||
ServerKickEvent event = bungee.getPluginManager().callEvent( new ServerKickEvent( con, kick.getMessage(), def ) );
|
ServerKickEvent event = bungee.getPluginManager().callEvent( new ServerKickEvent( con, kick.getMessage(), def, ServerKickEvent.State.CONNECTED ) );
|
||||||
if ( event.isCancelled() && event.getCancelServer() != null )
|
if ( event.isCancelled() && event.getCancelServer() != null )
|
||||||
{
|
{
|
||||||
con.connectNow( event.getCancelServer() );
|
con.connectNow( event.getCancelServer() );
|
||||||
|
@@ -1,8 +1,7 @@
|
|||||||
package net.md_5.bungee.connection;
|
package net.md_5.bungee.connection;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.ning.http.client.AsyncCompletionHandler;
|
import io.netty.util.concurrent.ScheduledFuture;
|
||||||
import com.ning.http.client.Response;
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
@@ -10,6 +9,7 @@ import java.security.GeneralSecurityException;
|
|||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.crypto.Cipher;
|
import javax.crypto.Cipher;
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
@@ -31,6 +31,7 @@ import net.md_5.bungee.api.connection.ProxiedPlayer;
|
|||||||
import net.md_5.bungee.api.event.LoginEvent;
|
import net.md_5.bungee.api.event.LoginEvent;
|
||||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||||
import net.md_5.bungee.api.event.ProxyPingEvent;
|
import net.md_5.bungee.api.event.ProxyPingEvent;
|
||||||
|
import net.md_5.bungee.http.HttpClient;
|
||||||
import net.md_5.bungee.netty.HandlerBoss;
|
import net.md_5.bungee.netty.HandlerBoss;
|
||||||
import net.md_5.bungee.netty.ChannelWrapper;
|
import net.md_5.bungee.netty.ChannelWrapper;
|
||||||
import net.md_5.bungee.netty.CipherDecoder;
|
import net.md_5.bungee.netty.CipherDecoder;
|
||||||
@@ -39,6 +40,7 @@ import net.md_5.bungee.netty.PacketDecoder;
|
|||||||
import net.md_5.bungee.netty.PacketHandler;
|
import net.md_5.bungee.netty.PacketHandler;
|
||||||
import net.md_5.bungee.netty.PipelineUtils;
|
import net.md_5.bungee.netty.PipelineUtils;
|
||||||
import net.md_5.bungee.protocol.Forge;
|
import net.md_5.bungee.protocol.Forge;
|
||||||
|
import net.md_5.bungee.protocol.MinecraftInput;
|
||||||
import net.md_5.bungee.protocol.Vanilla;
|
import net.md_5.bungee.protocol.Vanilla;
|
||||||
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
||||||
import net.md_5.bungee.protocol.packet.Packet1Login;
|
import net.md_5.bungee.protocol.packet.Packet1Login;
|
||||||
@@ -49,6 +51,7 @@ import net.md_5.bungee.protocol.packet.PacketFCEncryptionResponse;
|
|||||||
import net.md_5.bungee.protocol.packet.PacketFDEncryptionRequest;
|
import net.md_5.bungee.protocol.packet.PacketFDEncryptionRequest;
|
||||||
import net.md_5.bungee.protocol.packet.PacketFEPing;
|
import net.md_5.bungee.protocol.packet.PacketFEPing;
|
||||||
import net.md_5.bungee.protocol.packet.PacketFFKick;
|
import net.md_5.bungee.protocol.packet.PacketFFKick;
|
||||||
|
import net.md_5.bungee.api.AbstractReconnectHandler;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class InitialHandler extends PacketHandler implements PendingConnection
|
public class InitialHandler extends PacketHandler implements PendingConnection
|
||||||
@@ -77,6 +80,9 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
ch.write( packet );
|
ch.write( packet );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
private ScheduledFuture<?> pingFuture;
|
||||||
|
private InetSocketAddress vHost;
|
||||||
|
private byte version = -1;
|
||||||
|
|
||||||
private enum State
|
private enum State
|
||||||
{
|
{
|
||||||
@@ -99,6 +105,22 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
@Override
|
@Override
|
||||||
public void handle(PacketFAPluginMessage pluginMessage) throws Exception
|
public void handle(PacketFAPluginMessage pluginMessage) throws Exception
|
||||||
{
|
{
|
||||||
|
if ( pluginMessage.getTag().equals( "MC|PingHost" ) )
|
||||||
|
{
|
||||||
|
if ( pingFuture.cancel( false ) )
|
||||||
|
{
|
||||||
|
MinecraftInput in = pluginMessage.getMCStream();
|
||||||
|
version = in.readByte();
|
||||||
|
String connectHost = in.readString();
|
||||||
|
int connectPort = in.readInt();
|
||||||
|
this.vHost = new InetSocketAddress( connectHost, connectPort );
|
||||||
|
|
||||||
|
respondToPing();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Unregister?
|
// TODO: Unregister?
|
||||||
if ( pluginMessage.getTag().equals( "REGISTER" ) )
|
if ( pluginMessage.getTag().equals( "REGISTER" ) )
|
||||||
{
|
{
|
||||||
@@ -109,21 +131,53 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void respondToPing()
|
||||||
|
{
|
||||||
|
ServerInfo forced = AbstractReconnectHandler.getForcedHost( this );
|
||||||
|
final String motd = ( forced != null ) ? forced.getMotd() : listener.getMotd();
|
||||||
|
|
||||||
|
Callback<ServerPing> pingBack = new Callback<ServerPing>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void done(ServerPing result, Throwable error)
|
||||||
|
{
|
||||||
|
if ( error != null )
|
||||||
|
{
|
||||||
|
result = new ServerPing( (byte) -1, "-1", "Error pinging remote server: " + Util.exception( error ), -1, -1 );
|
||||||
|
}
|
||||||
|
result = bungee.getPluginManager().callEvent( new ProxyPingEvent( InitialHandler.this, result ) ).getResponse();
|
||||||
|
|
||||||
|
String kickMessage = ChatColor.DARK_BLUE
|
||||||
|
+ "\00" + result.getProtocolVersion()
|
||||||
|
+ "\00" + result.getGameVersion()
|
||||||
|
+ "\00" + result.getMotd()
|
||||||
|
+ "\00" + result.getCurrentPlayers()
|
||||||
|
+ "\00" + result.getMaxPlayers();
|
||||||
|
BungeeCord.getInstance().getConnectionThrottle().unthrottle( getAddress().getAddress() );
|
||||||
|
disconnect( kickMessage );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if ( forced != null && listener.isPingPassthrough() )
|
||||||
|
{
|
||||||
|
forced.ping( pingBack );
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
pingBack.done( new ServerPing( bungee.getProtocolVersion(), bungee.getGameVersion(), motd, bungee.getOnlineCount(), listener.getMaxPlayers() ), null );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(PacketFEPing ping) throws Exception
|
public void handle(PacketFEPing ping) throws Exception
|
||||||
{
|
{
|
||||||
ServerPing response = new ServerPing( bungee.getProtocolVersion(), bungee.getGameVersion(),
|
pingFuture = ch.getHandle().eventLoop().schedule( new Runnable()
|
||||||
listener.getMotd(), bungee.getOnlineCount(), listener.getMaxPlayers() );
|
{
|
||||||
|
@Override
|
||||||
response = bungee.getPluginManager().callEvent( new ProxyPingEvent( this, response ) ).getResponse();
|
public void run()
|
||||||
|
{
|
||||||
String kickMessage = ChatColor.DARK_BLUE
|
respondToPing();
|
||||||
+ "\00" + response.getProtocolVersion()
|
}
|
||||||
+ "\00" + response.getGameVersion()
|
}, 500, TimeUnit.MILLISECONDS );
|
||||||
+ "\00" + response.getMotd()
|
|
||||||
+ "\00" + response.getCurrentPlayers()
|
|
||||||
+ "\00" + response.getMaxPlayers();
|
|
||||||
disconnect( kickMessage );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -141,14 +195,15 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
{
|
{
|
||||||
Preconditions.checkState( thisState == State.HANDSHAKE, "Not expecting HANDSHAKE" );
|
Preconditions.checkState( thisState == State.HANDSHAKE, "Not expecting HANDSHAKE" );
|
||||||
this.handshake = handshake;
|
this.handshake = handshake;
|
||||||
|
this.vHost = new InetSocketAddress( handshake.getHost(), handshake.getPort() );
|
||||||
bungee.getLogger().log( Level.INFO, "{0} has connected", this );
|
bungee.getLogger().log( Level.INFO, "{0} has connected", this );
|
||||||
|
|
||||||
if ( handshake.getProcolVersion() > Vanilla.PROTOCOL_VERSION )
|
if ( handshake.getProcolVersion() > Vanilla.PROTOCOL_VERSION )
|
||||||
{
|
{
|
||||||
disconnect( "Outdated server!" );
|
disconnect( bungee.getTranslation( "outdated_server" ) );
|
||||||
} else if ( handshake.getProcolVersion() < Vanilla.PROTOCOL_VERSION )
|
} else if ( handshake.getProcolVersion() < Vanilla.PROTOCOL_VERSION )
|
||||||
{
|
{
|
||||||
disconnect( "Outdated client!" );
|
disconnect( bungee.getTranslation( "outdated_client" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( handshake.getUsername().length() > 16 )
|
if ( handshake.getUsername().length() > 16 )
|
||||||
@@ -184,7 +239,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
|
|
||||||
sharedKey = EncryptionUtil.getSecret( encryptResponse, request );
|
sharedKey = EncryptionUtil.getSecret( encryptResponse, request );
|
||||||
Cipher decrypt = EncryptionUtil.getCipher( Cipher.DECRYPT_MODE, sharedKey );
|
Cipher decrypt = EncryptionUtil.getCipher( Cipher.DECRYPT_MODE, sharedKey );
|
||||||
ch.getHandle().pipeline().addBefore( PipelineUtils.PACKET_DECODE_HANDLER, PipelineUtils.DECRYPT_HANDLER, new CipherDecoder( decrypt ) );
|
ch.addBefore( PipelineUtils.PACKET_DECODE_HANDLER, PipelineUtils.DECRYPT_HANDLER, new CipherDecoder( decrypt ) );
|
||||||
|
|
||||||
if ( BungeeCord.getInstance().config.isOnlineMode() )
|
if ( BungeeCord.getInstance().config.isOnlineMode() )
|
||||||
{
|
{
|
||||||
@@ -201,35 +256,37 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
|
|
||||||
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;
|
||||||
bungee.getHttpClient().prepareGet( authURL ).execute( new AsyncCompletionHandler<Response>()
|
|
||||||
|
Callback<String> handler = new Callback<String>()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public Response onCompleted(Response response) throws Exception
|
public void done(String result, Throwable error)
|
||||||
{
|
{
|
||||||
if ( "YES".equals( response.getResponseBody() ) )
|
if ( error == null )
|
||||||
|
{
|
||||||
|
if ( "YES".equals( result ) )
|
||||||
{
|
{
|
||||||
finish();
|
finish();
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
disconnect( "Not authenticated with Minecraft.net" );
|
disconnect( "Not authenticated with Minecraft.net" );
|
||||||
}
|
}
|
||||||
return response;
|
} else
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onThrowable(Throwable t)
|
|
||||||
{
|
{
|
||||||
disconnect( bungee.getTranslation( "mojang_fail" ) );
|
disconnect( bungee.getTranslation( "mojang_fail" ) );
|
||||||
bungee.getLogger().log( Level.SEVERE, "Error authenticating " + getName() + " with minecraft.net", t );
|
bungee.getLogger().log( Level.SEVERE, "Error authenticating " + getName() + " with minecraft.net", error );
|
||||||
}
|
}
|
||||||
} );
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpClient.get( authURL, ch.getHandle().eventLoop(), handler );
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void finish() throws GeneralSecurityException
|
private void finish()
|
||||||
{
|
{
|
||||||
// Check for multiple connections
|
// Check for multiple connections
|
||||||
ProxiedPlayer old = bungee.getPlayer( handshake.getUsername() );
|
ProxiedPlayer old = bungee.getPlayer( handshake.getUsername() );
|
||||||
@@ -257,17 +314,20 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void run()
|
public void run()
|
||||||
|
{
|
||||||
|
if ( ch.getHandle().isActive() )
|
||||||
{
|
{
|
||||||
unsafe().sendPacket( new PacketFCEncryptionResponse( new byte[ 0 ], new byte[ 0 ] ) );
|
unsafe().sendPacket( new PacketFCEncryptionResponse( new byte[ 0 ], new byte[ 0 ] ) );
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Cipher encrypt = EncryptionUtil.getCipher( Cipher.ENCRYPT_MODE, sharedKey );
|
Cipher encrypt = EncryptionUtil.getCipher( Cipher.ENCRYPT_MODE, sharedKey );
|
||||||
ch.getHandle().pipeline().addBefore( PipelineUtils.DECRYPT_HANDLER, PipelineUtils.ENCRYPT_HANDLER, new CipherEncoder( encrypt ) );
|
ch.addBefore( PipelineUtils.DECRYPT_HANDLER, PipelineUtils.ENCRYPT_HANDLER, new CipherEncoder( encrypt ) );
|
||||||
} catch ( GeneralSecurityException ex )
|
} catch ( GeneralSecurityException ex )
|
||||||
{
|
{
|
||||||
disconnect( "Cipher error: " + Util.exception( ex ) );
|
disconnect( "Cipher error: " + Util.exception( ex ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -281,14 +341,21 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
{
|
{
|
||||||
Preconditions.checkState( thisState == State.LOGIN, "Not expecting LOGIN" );
|
Preconditions.checkState( thisState == State.LOGIN, "Not expecting LOGIN" );
|
||||||
|
|
||||||
UserConnection userCon = new UserConnection( (BungeeCord) bungee, ch, getName(), this );
|
UserConnection userCon = new UserConnection( bungee, ch, getName(), this );
|
||||||
userCon.init();
|
userCon.init();
|
||||||
|
|
||||||
bungee.getPluginManager().callEvent( new PostLoginEvent( userCon ) );
|
bungee.getPluginManager().callEvent( new PostLoginEvent( userCon ) );
|
||||||
|
|
||||||
ch.getHandle().pipeline().get( HandlerBoss.class ).setHandler( new UpstreamBridge( bungee, userCon ) );
|
ch.getHandle().pipeline().get( HandlerBoss.class ).setHandler( new UpstreamBridge( bungee, userCon ) );
|
||||||
|
|
||||||
ServerInfo server = bungee.getReconnectHandler().getServer( userCon );
|
ServerInfo server;
|
||||||
|
if ( bungee.getReconnectHandler() != null )
|
||||||
|
{
|
||||||
|
server = bungee.getReconnectHandler().getServer( userCon );
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
server = AbstractReconnectHandler.getForcedHost( this );
|
||||||
|
}
|
||||||
userCon.connect( server, true );
|
userCon.connect( server, true );
|
||||||
|
|
||||||
thisState = State.FINISHED;
|
thisState = State.FINISHED;
|
||||||
@@ -314,13 +381,13 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
@Override
|
@Override
|
||||||
public byte getVersion()
|
public byte getVersion()
|
||||||
{
|
{
|
||||||
return ( handshake == null ) ? -1 : handshake.getProcolVersion();
|
return ( handshake == null ) ? version : handshake.getProcolVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InetSocketAddress getVirtualHost()
|
public InetSocketAddress getVirtualHost()
|
||||||
{
|
{
|
||||||
return ( handshake == null ) ? null : new InetSocketAddress( handshake.getHost(), handshake.getPort() );
|
return vHost;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
package net.md_5.bungee.connection;
|
package net.md_5.bungee.connection;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import net.md_5.bungee.api.Callback;
|
import net.md_5.bungee.api.Callback;
|
||||||
import net.md_5.bungee.api.ServerPing;
|
import net.md_5.bungee.api.ServerPing;
|
||||||
@@ -14,15 +16,15 @@ public class PingHandler extends PacketHandler
|
|||||||
|
|
||||||
private final ServerInfo target;
|
private final ServerInfo target;
|
||||||
private final Callback<ServerPing> callback;
|
private final Callback<ServerPing> callback;
|
||||||
private static final byte[] pingBuf = new byte[]
|
|
||||||
{
|
|
||||||
(byte) 0xFE, (byte) 0x01
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void connected(ChannelWrapper channel) throws Exception
|
public void connected(ChannelWrapper channel) throws Exception
|
||||||
{
|
{
|
||||||
channel.write( pingBuf );
|
// TODO: Update this to 1.6.2 style!
|
||||||
|
channel.write( Unpooled.wrappedBuffer( new byte[]
|
||||||
|
{
|
||||||
|
(byte) 0xFE, (byte) 0x01
|
||||||
|
} ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -5,16 +5,19 @@ import net.md_5.bungee.EntityMap;
|
|||||||
import net.md_5.bungee.UserConnection;
|
import net.md_5.bungee.UserConnection;
|
||||||
import net.md_5.bungee.Util;
|
import net.md_5.bungee.Util;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.config.TexturePackInfo;
|
|
||||||
import net.md_5.bungee.api.event.ChatEvent;
|
import net.md_5.bungee.api.event.ChatEvent;
|
||||||
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
|
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
|
||||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||||
import net.md_5.bungee.netty.ChannelWrapper;
|
import net.md_5.bungee.netty.ChannelWrapper;
|
||||||
import net.md_5.bungee.netty.PacketHandler;
|
import net.md_5.bungee.netty.PacketHandler;
|
||||||
|
import net.md_5.bungee.netty.PacketWrapper;
|
||||||
import net.md_5.bungee.protocol.packet.Packet0KeepAlive;
|
import net.md_5.bungee.protocol.packet.Packet0KeepAlive;
|
||||||
import net.md_5.bungee.protocol.packet.Packet3Chat;
|
import net.md_5.bungee.protocol.packet.Packet3Chat;
|
||||||
|
import net.md_5.bungee.protocol.packet.PacketCBTabComplete;
|
||||||
import net.md_5.bungee.protocol.packet.PacketCCSettings;
|
import net.md_5.bungee.protocol.packet.PacketCCSettings;
|
||||||
import net.md_5.bungee.protocol.packet.PacketFAPluginMessage;
|
import net.md_5.bungee.protocol.packet.PacketFAPluginMessage;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class UpstreamBridge extends PacketHandler
|
public class UpstreamBridge extends PacketHandler
|
||||||
{
|
{
|
||||||
@@ -30,12 +33,6 @@ public class UpstreamBridge extends PacketHandler
|
|||||||
BungeeCord.getInstance().addConnection( con );
|
BungeeCord.getInstance().addConnection( con );
|
||||||
con.getTabList().onConnect();
|
con.getTabList().onConnect();
|
||||||
con.unsafe().sendPacket( BungeeCord.getInstance().registerChannels() );
|
con.unsafe().sendPacket( BungeeCord.getInstance().registerChannels() );
|
||||||
|
|
||||||
TexturePackInfo texture = con.getPendingConnection().getListener().getTexturePack();
|
|
||||||
if ( texture != null )
|
|
||||||
{
|
|
||||||
con.setTexturePack( texture );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -60,12 +57,12 @@ public class UpstreamBridge extends PacketHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(byte[] buf) throws Exception
|
public void handle(PacketWrapper packet) throws Exception
|
||||||
{
|
{
|
||||||
EntityMap.rewrite( buf, con.getClientEntityId(), con.getServerEntityId() );
|
EntityMap.rewrite( packet.buf, con.getClientEntityId(), con.getServerEntityId() );
|
||||||
if ( con.getServer() != null )
|
if ( con.getServer() != null )
|
||||||
{
|
{
|
||||||
con.getServer().getCh().write( buf );
|
con.getServer().getCh().write( packet );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,14 +81,28 @@ public class UpstreamBridge extends PacketHandler
|
|||||||
public void handle(Packet3Chat chat) throws Exception
|
public void handle(Packet3Chat chat) throws Exception
|
||||||
{
|
{
|
||||||
ChatEvent chatEvent = new ChatEvent( con, con.getServer(), chat.getMessage() );
|
ChatEvent chatEvent = new ChatEvent( con, con.getServer(), chat.getMessage() );
|
||||||
if ( bungee.getPluginManager().callEvent( chatEvent ).isCancelled() )
|
if ( !bungee.getPluginManager().callEvent( chatEvent ).isCancelled() )
|
||||||
{
|
{
|
||||||
|
chat.setMessage( chatEvent.getMessage() );
|
||||||
|
if ( !chatEvent.isCommand() || !bungee.getPluginManager().dispatchCommand( con, chat.getMessage().substring( 1 ) ) )
|
||||||
|
{
|
||||||
|
con.getServer().unsafe().sendPacket( chat );
|
||||||
|
}
|
||||||
|
}
|
||||||
throw new CancelSendSignal();
|
throw new CancelSendSignal();
|
||||||
}
|
}
|
||||||
if ( chatEvent.isCommand() )
|
|
||||||
|
@Override
|
||||||
|
public void handle(PacketCBTabComplete tabComplete) throws Exception
|
||||||
{
|
{
|
||||||
if ( bungee.getPluginManager().dispatchCommand( con, chat.getMessage().substring( 1 ) ) )
|
if ( tabComplete.getCursor().startsWith( "/" ) )
|
||||||
{
|
{
|
||||||
|
List<String> results = new ArrayList<>();
|
||||||
|
bungee.getPluginManager().dispatchCommand( con, tabComplete.getCursor().substring( 1, tabComplete.getCursor().length() ), results );
|
||||||
|
|
||||||
|
if ( !results.isEmpty() )
|
||||||
|
{
|
||||||
|
con.unsafe().sendPacket( new PacketCBTabComplete( results.toArray( new String[ results.size() ] ) ) );
|
||||||
throw new CancelSendSignal();
|
throw new CancelSendSignal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,7 +122,7 @@ public class UpstreamBridge extends PacketHandler
|
|||||||
throw new CancelSendSignal();
|
throw new CancelSendSignal();
|
||||||
}
|
}
|
||||||
// Hack around Forge race conditions
|
// Hack around Forge race conditions
|
||||||
if ( pluginMessage.getTag().equals( "FML" ) && ( pluginMessage.getData()[0] & 0xFF ) == 1 )
|
if ( pluginMessage.getTag().equals( "FML" ) && pluginMessage.getStream().readUnsignedByte() == 1 )
|
||||||
{
|
{
|
||||||
throw new CancelSendSignal();
|
throw new CancelSendSignal();
|
||||||
}
|
}
|
||||||
|
77
proxy/src/main/java/net/md_5/bungee/http/HttpClient.java
Normal file
77
proxy/src/main/java/net/md_5/bungee/http/HttpClient.java
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
package net.md_5.bungee.http;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import io.netty.bootstrap.Bootstrap;
|
||||||
|
import io.netty.channel.ChannelFuture;
|
||||||
|
import io.netty.channel.ChannelFutureListener;
|
||||||
|
import io.netty.channel.ChannelOption;
|
||||||
|
import io.netty.channel.EventLoop;
|
||||||
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
|
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||||
|
import io.netty.handler.codec.http.DefaultHttpRequest;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaders;
|
||||||
|
import io.netty.handler.codec.http.HttpMethod;
|
||||||
|
import io.netty.handler.codec.http.HttpRequest;
|
||||||
|
import io.netty.handler.codec.http.HttpVersion;
|
||||||
|
import java.net.URI;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import net.md_5.bungee.api.Callback;
|
||||||
|
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class HttpClient
|
||||||
|
{
|
||||||
|
|
||||||
|
public static int TIMEOUT = 5000;
|
||||||
|
|
||||||
|
public static void get(String url, EventLoop eventLoop, final Callback<String> callback)
|
||||||
|
{
|
||||||
|
Preconditions.checkNotNull( url, "url" );
|
||||||
|
Preconditions.checkNotNull( eventLoop, "eventLoop" );
|
||||||
|
Preconditions.checkNotNull( callback, "callBack" );
|
||||||
|
|
||||||
|
final URI uri = URI.create( url );
|
||||||
|
|
||||||
|
Preconditions.checkNotNull( uri.getScheme(), "scheme" );
|
||||||
|
Preconditions.checkNotNull( uri.getHost(), "host" );
|
||||||
|
boolean ssl = uri.getScheme().equals( "https" );
|
||||||
|
int port = uri.getPort();
|
||||||
|
if ( port == -1 )
|
||||||
|
{
|
||||||
|
switch ( uri.getScheme() )
|
||||||
|
{
|
||||||
|
case "http":
|
||||||
|
port = 80;
|
||||||
|
break;
|
||||||
|
case "https":
|
||||||
|
port = 443;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException( "Unknown scheme " + uri.getScheme() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelFutureListener future = new ChannelFutureListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void operationComplete(ChannelFuture future) throws Exception
|
||||||
|
{
|
||||||
|
if ( future.isSuccess() )
|
||||||
|
{
|
||||||
|
String path = uri.getRawPath() + ( ( uri.getRawQuery() == null ) ? "" : "?" + uri.getRawQuery() );
|
||||||
|
|
||||||
|
HttpRequest request = new DefaultHttpRequest( HttpVersion.HTTP_1_1, HttpMethod.GET, path );
|
||||||
|
request.headers().set( HttpHeaders.Names.HOST, uri.getHost() );
|
||||||
|
|
||||||
|
future.channel().writeAndFlush( request );
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
callback.done( null, future.cause() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
new Bootstrap().channel( NioSocketChannel.class ).group( eventLoop ).handler( new HttpInitializer( callback, ssl ) ).
|
||||||
|
option( ChannelOption.CONNECT_TIMEOUT_MILLIS, TIMEOUT ).remoteAddress( uri.getHost(), port ).connect().addListener( future );
|
||||||
|
}
|
||||||
|
}
|
61
proxy/src/main/java/net/md_5/bungee/http/HttpHandler.java
Normal file
61
proxy/src/main/java/net/md_5/bungee/http/HttpHandler.java
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package net.md_5.bungee.http;
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
|
import io.netty.handler.codec.http.HttpContent;
|
||||||
|
import io.netty.handler.codec.http.HttpObject;
|
||||||
|
import io.netty.handler.codec.http.HttpResponse;
|
||||||
|
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||||
|
import io.netty.handler.codec.http.LastHttpContent;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import net.md_5.bungee.api.Callback;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class HttpHandler extends SimpleChannelInboundHandler<HttpObject>
|
||||||
|
{
|
||||||
|
|
||||||
|
private final Callback<String> callback;
|
||||||
|
private final StringBuilder buffer = new StringBuilder();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
callback.done( null, cause );
|
||||||
|
} finally
|
||||||
|
{
|
||||||
|
ctx.channel().close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception
|
||||||
|
{
|
||||||
|
if ( msg instanceof HttpResponse )
|
||||||
|
{
|
||||||
|
HttpResponse response = (HttpResponse) msg;
|
||||||
|
if ( response.getStatus().code() != 200 )
|
||||||
|
{
|
||||||
|
throw new IllegalStateException( "Expected HTTP response 200 OK, got " + response.getStatus() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( msg instanceof HttpContent )
|
||||||
|
{
|
||||||
|
HttpContent content = (HttpContent) msg;
|
||||||
|
buffer.append( content.content().toString( Charset.forName( "UTF-8" ) ) );
|
||||||
|
|
||||||
|
if ( msg instanceof LastHttpContent )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
callback.done( buffer.toString(), null );
|
||||||
|
} finally
|
||||||
|
{
|
||||||
|
ctx.channel().close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,42 @@
|
|||||||
|
package net.md_5.bungee.http;
|
||||||
|
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelInitializer;
|
||||||
|
import io.netty.handler.codec.http.HttpClientCodec;
|
||||||
|
import io.netty.handler.ssl.SslHandler;
|
||||||
|
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLEngine;
|
||||||
|
import javax.net.ssl.TrustManager;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import net.md_5.bungee.api.Callback;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class HttpInitializer extends ChannelInitializer<Channel>
|
||||||
|
{
|
||||||
|
|
||||||
|
private final Callback<String> callback;
|
||||||
|
private final boolean ssl;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initChannel(Channel ch) throws Exception
|
||||||
|
{
|
||||||
|
ch.pipeline().addLast( "timeout", new ReadTimeoutHandler( HttpClient.TIMEOUT, TimeUnit.MILLISECONDS ) );
|
||||||
|
if ( ssl )
|
||||||
|
{
|
||||||
|
SSLContext context = SSLContext.getInstance( "TLS" );
|
||||||
|
context.init( null, new TrustManager[]
|
||||||
|
{
|
||||||
|
TrustingX509Manager.getInstance()
|
||||||
|
}, null );
|
||||||
|
|
||||||
|
SSLEngine engine = context.createSSLEngine();
|
||||||
|
engine.setUseClientMode( true );
|
||||||
|
|
||||||
|
ch.pipeline().addLast( "ssl", new SslHandler( engine ) );
|
||||||
|
}
|
||||||
|
ch.pipeline().addLast( "http", new HttpClientCodec() );
|
||||||
|
ch.pipeline().addLast( "handler", new HttpHandler( callback ) );
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,32 @@
|
|||||||
|
package net.md_5.bungee.http;
|
||||||
|
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import javax.net.ssl.X509TrustManager;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class TrustingX509Manager implements X509TrustManager
|
||||||
|
{
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private static final X509TrustManager instance = new TrustingX509Manager();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public X509Certificate[] getAcceptedIssuers()
|
||||||
|
{
|
||||||
|
return new X509Certificate[ 0 ];
|
||||||
|
}
|
||||||
|
}
|
@@ -12,7 +12,7 @@ public class LogDispatcher extends Thread
|
|||||||
|
|
||||||
public LogDispatcher(BungeeLogger logger)
|
public LogDispatcher(BungeeLogger logger)
|
||||||
{
|
{
|
||||||
super( "BungeeCord Logger Thread - " + logger );
|
super( "BungeeCord Logger Thread" );
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
package net.md_5.bungee.netty;
|
package net.md_5.bungee.netty;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@@ -19,9 +21,17 @@ public class ChannelWrapper
|
|||||||
public synchronized void write(Object packet)
|
public synchronized void write(Object packet)
|
||||||
{
|
{
|
||||||
if ( !closed )
|
if ( !closed )
|
||||||
|
{
|
||||||
|
if ( packet instanceof PacketWrapper )
|
||||||
|
{
|
||||||
|
( (PacketWrapper) packet ).setReleased( true );
|
||||||
|
ch.write( ( (PacketWrapper) packet ).buf );
|
||||||
|
} else
|
||||||
{
|
{
|
||||||
ch.write( packet );
|
ch.write( packet );
|
||||||
}
|
}
|
||||||
|
ch.flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void close()
|
public synchronized void close()
|
||||||
@@ -29,10 +39,18 @@ public class ChannelWrapper
|
|||||||
if ( !closed )
|
if ( !closed )
|
||||||
{
|
{
|
||||||
closed = true;
|
closed = true;
|
||||||
|
ch.flush();
|
||||||
ch.close();
|
ch.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addBefore(String baseName, String name, ChannelHandler handler)
|
||||||
|
{
|
||||||
|
Preconditions.checkState( ch.eventLoop().inEventLoop(), "cannot add handler outside of event loop" );
|
||||||
|
ch.pipeline().flush();
|
||||||
|
ch.pipeline().addBefore( baseName, name, handler );
|
||||||
|
}
|
||||||
|
|
||||||
public Channel getHandle()
|
public Channel getHandle()
|
||||||
{
|
{
|
||||||
return ch;
|
return ch;
|
||||||
|
@@ -51,7 +51,7 @@ public class CipherBase
|
|||||||
byte[] heapIn = bufToByte( in );
|
byte[] heapIn = bufToByte( in );
|
||||||
|
|
||||||
ByteBuf heapOut = ctx.alloc().heapBuffer( cipher.getOutputSize( readableBytes ) );
|
ByteBuf heapOut = ctx.alloc().heapBuffer( cipher.getOutputSize( readableBytes ) );
|
||||||
heapOut.writerIndex( cipher.update( heapIn, 0, readableBytes, heapOut.array(), heapOut.arrayOffset() ));
|
heapOut.writerIndex( cipher.update( heapIn, 0, readableBytes, heapOut.array(), heapOut.arrayOffset() ) );
|
||||||
|
|
||||||
return heapOut;
|
return heapOut;
|
||||||
}
|
}
|
||||||
|
@@ -2,8 +2,8 @@ package net.md_5.bungee.netty;
|
|||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.MessageList;
|
|
||||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||||
|
import java.util.List;
|
||||||
import javax.crypto.Cipher;
|
import javax.crypto.Cipher;
|
||||||
|
|
||||||
public class CipherDecoder extends MessageToMessageDecoder<ByteBuf>
|
public class CipherDecoder extends MessageToMessageDecoder<ByteBuf>
|
||||||
@@ -17,7 +17,7 @@ public class CipherDecoder extends MessageToMessageDecoder<ByteBuf>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, MessageList<Object> out) throws Exception
|
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception
|
||||||
{
|
{
|
||||||
out.add( cipher.cipher( ctx, msg ) );
|
out.add( cipher.cipher( ctx, msg ) );
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,6 @@ package net.md_5.bungee.netty;
|
|||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||||
import io.netty.channel.MessageList;
|
|
||||||
import io.netty.handler.timeout.ReadTimeoutException;
|
import io.netty.handler.timeout.ReadTimeoutException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
@@ -59,30 +58,31 @@ public class HandlerBoss extends ChannelInboundHandlerAdapter
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void messageReceived(ChannelHandlerContext ctx, MessageList<Object> msgs) throws Exception
|
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
|
||||||
{
|
{
|
||||||
for ( Object msg : msgs )
|
if ( handler != null )
|
||||||
{
|
|
||||||
if ( handler != null && ctx.channel().isActive() )
|
|
||||||
{
|
|
||||||
if ( msg instanceof PacketWrapper )
|
|
||||||
{
|
{
|
||||||
|
PacketWrapper packet = (PacketWrapper) msg;
|
||||||
boolean sendPacket = true;
|
boolean sendPacket = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
( (PacketWrapper) msg ).packet.handle( handler );
|
if ( packet.packet != null )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
packet.packet.handle( handler );
|
||||||
} catch ( CancelSendSignal ex )
|
} catch ( CancelSendSignal ex )
|
||||||
{
|
{
|
||||||
sendPacket = false;
|
sendPacket = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if ( sendPacket )
|
if ( sendPacket )
|
||||||
{
|
{
|
||||||
handler.handle( ( (PacketWrapper) msg ).buf );
|
handler.handle( packet );
|
||||||
}
|
}
|
||||||
} else
|
} finally
|
||||||
{
|
{
|
||||||
handler.handle( (byte[]) msg );
|
packet.trySingleRelease();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,8 +2,8 @@ package net.md_5.bungee.netty;
|
|||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.MessageList;
|
|
||||||
import io.netty.handler.codec.ReplayingDecoder;
|
import io.netty.handler.codec.ReplayingDecoder;
|
||||||
|
import java.util.List;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@@ -28,7 +28,7 @@ public class PacketDecoder extends ReplayingDecoder<Void>
|
|||||||
private Protocol protocol;
|
private Protocol protocol;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList<Object> out) throws Exception
|
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception
|
||||||
{
|
{
|
||||||
// While we have enough data
|
// While we have enough data
|
||||||
while ( true )
|
while ( true )
|
||||||
@@ -40,24 +40,11 @@ public class PacketDecoder extends ReplayingDecoder<Void>
|
|||||||
// If we got this far, it means we have formed a packet, so lets grab the end index
|
// If we got this far, it means we have formed a packet, so lets grab the end index
|
||||||
int endIndex = in.readerIndex();
|
int endIndex = in.readerIndex();
|
||||||
// Allocate a buffer big enough for all bytes we have read
|
// Allocate a buffer big enough for all bytes we have read
|
||||||
byte[] buf = new byte[ endIndex - startIndex ];
|
ByteBuf buf = in.copy( startIndex, endIndex - startIndex );
|
||||||
// Go back to start index
|
|
||||||
in.readerIndex( startIndex );
|
|
||||||
// Drain all the bytes into our buffer
|
|
||||||
in.readBytes( buf, 0, buf.length );
|
|
||||||
// Jump back to the end of this packet
|
|
||||||
in.readerIndex( endIndex );
|
|
||||||
// Checkpoint our state incase we don't have enough data for another packet
|
// Checkpoint our state incase we don't have enough data for another packet
|
||||||
checkpoint();
|
checkpoint();
|
||||||
|
|
||||||
// Store our decoded message
|
// Store our decoded message
|
||||||
if ( packet != null )
|
|
||||||
{
|
|
||||||
out.add( new PacketWrapper( packet, buf ) );
|
out.add( new PacketWrapper( packet, buf ) );
|
||||||
} else
|
|
||||||
{
|
|
||||||
out.add( buf );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,7 @@ public abstract class PacketHandler extends net.md_5.bungee.protocol.packet.Abst
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handle(byte[] buf) throws Exception
|
public void handle(PacketWrapper packet) throws Exception
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,16 +1,25 @@
|
|||||||
package net.md_5.bungee.netty;
|
package net.md_5.bungee.netty;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class PacketWrapper
|
public class PacketWrapper
|
||||||
{
|
{
|
||||||
|
|
||||||
DefinedPacket packet;
|
public final DefinedPacket packet;
|
||||||
byte[] buf;
|
public final ByteBuf buf;
|
||||||
|
@Setter
|
||||||
|
private boolean released;
|
||||||
|
|
||||||
public PacketWrapper(DefinedPacket packet, byte[] buf)
|
public void trySingleRelease()
|
||||||
{
|
{
|
||||||
this.packet = packet;
|
if ( !released )
|
||||||
this.buf = buf;
|
{
|
||||||
|
buf.release();
|
||||||
|
released = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,9 +4,9 @@ import io.netty.channel.Channel;
|
|||||||
import io.netty.channel.ChannelException;
|
import io.netty.channel.ChannelException;
|
||||||
import io.netty.channel.ChannelInitializer;
|
import io.netty.channel.ChannelInitializer;
|
||||||
import io.netty.channel.ChannelOption;
|
import io.netty.channel.ChannelOption;
|
||||||
import io.netty.handler.codec.bytes.ByteArrayEncoder;
|
|
||||||
import io.netty.handler.timeout.ReadTimeoutHandler;
|
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||||
import io.netty.util.AttributeKey;
|
import io.netty.util.AttributeKey;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import net.md_5.bungee.BungeeCord;
|
import net.md_5.bungee.BungeeCord;
|
||||||
import net.md_5.bungee.BungeeServerInfo;
|
import net.md_5.bungee.BungeeServerInfo;
|
||||||
@@ -28,6 +28,12 @@ public class PipelineUtils
|
|||||||
@Override
|
@Override
|
||||||
protected void initChannel(Channel ch) throws Exception
|
protected void initChannel(Channel ch) throws Exception
|
||||||
{
|
{
|
||||||
|
if ( BungeeCord.getInstance().getConnectionThrottle().throttle( ( (InetSocketAddress) ch.remoteAddress() ).getAddress() ) )
|
||||||
|
{
|
||||||
|
ch.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
BASE.initChannel( ch );
|
BASE.initChannel( ch );
|
||||||
ch.pipeline().get( HandlerBoss.class ).setHandler( new InitialHandler( ProxyServer.getInstance(), ch.attr( LISTENER ).get() ) );
|
ch.pipeline().get( HandlerBoss.class ).setHandler( new InitialHandler( ProxyServer.getInstance(), ch.attr( LISTENER ).get() ) );
|
||||||
}
|
}
|
||||||
@@ -43,11 +49,9 @@ public class PipelineUtils
|
|||||||
};
|
};
|
||||||
public static final Base BASE = new Base();
|
public static final Base BASE = new Base();
|
||||||
private static final DefinedPacketEncoder packetEncoder = new DefinedPacketEncoder();
|
private static final DefinedPacketEncoder packetEncoder = new DefinedPacketEncoder();
|
||||||
private static final ByteArrayEncoder arrayEncoder = new ByteArrayEncoder();
|
|
||||||
public static String TIMEOUT_HANDLER = "timeout";
|
public static String TIMEOUT_HANDLER = "timeout";
|
||||||
public static String PACKET_DECODE_HANDLER = "packet-decoder";
|
public static String PACKET_DECODE_HANDLER = "packet-decoder";
|
||||||
public static String PACKET_ENCODE_HANDLER = "packet-encoder";
|
public static String PACKET_ENCODE_HANDLER = "packet-encoder";
|
||||||
public static String ARRAY_ENCODE_HANDLER = "array-encoder";
|
|
||||||
public static String BOSS_HANDLER = "inbound-boss";
|
public static String BOSS_HANDLER = "inbound-boss";
|
||||||
public static String ENCRYPT_HANDLER = "encrypt";
|
public static String ENCRYPT_HANDLER = "encrypt";
|
||||||
public static String DECRYPT_HANDLER = "decrypt";
|
public static String DECRYPT_HANDLER = "decrypt";
|
||||||
@@ -69,7 +73,6 @@ public class PipelineUtils
|
|||||||
ch.pipeline().addLast( TIMEOUT_HANDLER, new ReadTimeoutHandler( BungeeCord.getInstance().config.getTimeout(), TimeUnit.MILLISECONDS ) );
|
ch.pipeline().addLast( TIMEOUT_HANDLER, new ReadTimeoutHandler( BungeeCord.getInstance().config.getTimeout(), TimeUnit.MILLISECONDS ) );
|
||||||
ch.pipeline().addLast( PACKET_DECODE_HANDLER, new PacketDecoder( Vanilla.getInstance() ) );
|
ch.pipeline().addLast( PACKET_DECODE_HANDLER, new PacketDecoder( Vanilla.getInstance() ) );
|
||||||
ch.pipeline().addLast( PACKET_ENCODE_HANDLER, packetEncoder );
|
ch.pipeline().addLast( PACKET_ENCODE_HANDLER, packetEncoder );
|
||||||
ch.pipeline().addLast( ARRAY_ENCODE_HANDLER, arrayEncoder );
|
|
||||||
ch.pipeline().addLast( BOSS_HANDLER, new HandlerBoss() );
|
ch.pipeline().addLast( BOSS_HANDLER, new HandlerBoss() );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -1,36 +0,0 @@
|
|||||||
package net.md_5.bungee.reconnect;
|
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
|
||||||
import net.md_5.bungee.api.ReconnectHandler;
|
|
||||||
import net.md_5.bungee.api.config.ListenerInfo;
|
|
||||||
import net.md_5.bungee.api.config.ServerInfo;
|
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
|
||||||
|
|
||||||
public abstract class AbstractReconnectManager implements ReconnectHandler
|
|
||||||
{
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ServerInfo getServer(ProxiedPlayer player)
|
|
||||||
{
|
|
||||||
ListenerInfo listener = player.getPendingConnection().getListener();
|
|
||||||
String name;
|
|
||||||
String forced = listener.getForcedHosts().get( player.getPendingConnection().getVirtualHost().getHostString() );
|
|
||||||
if ( forced == null && listener.isForceDefault() )
|
|
||||||
{
|
|
||||||
forced = listener.getDefaultServer();
|
|
||||||
}
|
|
||||||
|
|
||||||
String server = ( forced == null ) ? getStoredServer( player ) : forced;
|
|
||||||
name = ( server != null ) ? server : listener.getDefaultServer();
|
|
||||||
ServerInfo info = ProxyServer.getInstance().getServerInfo( name );
|
|
||||||
if ( info == null )
|
|
||||||
{
|
|
||||||
info = ProxyServer.getInstance().getServerInfo( listener.getDefaultServer() );
|
|
||||||
}
|
|
||||||
Preconditions.checkState( info != null, "Default server not defined" );
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract String getStoredServer(ProxiedPlayer player);
|
|
||||||
}
|
|
@@ -1,94 +0,0 @@
|
|||||||
package net.md_5.bungee.reconnect;
|
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.DriverManager;
|
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
|
||||||
|
|
||||||
public class SQLReconnectHandler extends AbstractReconnectManager
|
|
||||||
{
|
|
||||||
|
|
||||||
private final Connection connection;
|
|
||||||
|
|
||||||
public SQLReconnectHandler() throws ClassNotFoundException, SQLException
|
|
||||||
{
|
|
||||||
Class.forName( "org.sqlite.JDBC" );
|
|
||||||
connection = DriverManager.getConnection( "jdbc:sqlite:bungee.sqlite" );
|
|
||||||
|
|
||||||
try ( PreparedStatement ps = connection.prepareStatement(
|
|
||||||
"CREATE TABLE IF NOT EXISTS players ("
|
|
||||||
+ "playerId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
|
|
||||||
+ "username TEXT NOT NULL UNIQUE COLLATE NOCASE,"
|
|
||||||
+ "seen INTEGER,"
|
|
||||||
+ "server TEXT"
|
|
||||||
+ ");" ) )
|
|
||||||
{
|
|
||||||
ps.executeUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getStoredServer(ProxiedPlayer player)
|
|
||||||
{
|
|
||||||
String server = null;
|
|
||||||
try ( PreparedStatement ps = connection.prepareStatement( "SELECT server FROM players WHERE username = ?" ) )
|
|
||||||
{
|
|
||||||
ps.setString( 1, player.getName() );
|
|
||||||
try ( ResultSet rs = ps.executeQuery() )
|
|
||||||
{
|
|
||||||
if ( rs.next() )
|
|
||||||
{
|
|
||||||
server = rs.getString( 1 );
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
try ( PreparedStatement playerUpdate = connection.prepareStatement( "INSERT INTO players( username ) VALUES( ? )" ) )
|
|
||||||
{
|
|
||||||
playerUpdate.setString( 1, player.getName() );
|
|
||||||
playerUpdate.executeUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch ( SQLException ex )
|
|
||||||
{
|
|
||||||
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not load location for player " + player.getName(), ex );
|
|
||||||
}
|
|
||||||
return server;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setServer(ProxiedPlayer player)
|
|
||||||
{
|
|
||||||
|
|
||||||
try ( PreparedStatement ps = connection.prepareStatement( "UPDATE players SET server = ?, seen = ? WHERE username = ?" ) )
|
|
||||||
{
|
|
||||||
ps.setString( 1, player.getServer().getInfo().getName() );
|
|
||||||
ps.setInt( 2, (int) ( System.currentTimeMillis() / 1000L ) );
|
|
||||||
ps.setString( 3, player.getName() );
|
|
||||||
ps.executeUpdate();
|
|
||||||
} catch ( SQLException ex )
|
|
||||||
{
|
|
||||||
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not save location for player " + player.getName() + " on server " + player.getServer().getInfo().getName(), ex );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
connection.close();
|
|
||||||
} catch ( SQLException ex )
|
|
||||||
{
|
|
||||||
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Error closing SQLite connection", ex );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -0,0 +1,114 @@
|
|||||||
|
package net.md_5.bungee.reconnect;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.AbstractReconnectHandler;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
|
import net.md_5.bungee.api.config.ServerInfo;
|
||||||
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
import org.yaml.snakeyaml.Yaml;
|
||||||
|
import org.yaml.snakeyaml.error.YAMLException;
|
||||||
|
|
||||||
|
public class YamlReconnectHandler extends AbstractReconnectHandler
|
||||||
|
{
|
||||||
|
|
||||||
|
private final Yaml yaml = new Yaml();
|
||||||
|
private final File file = new File( "locations.yml" );
|
||||||
|
private final ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||||
|
/*========================================================================*/
|
||||||
|
private Map<String, String> data;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public YamlReconnectHandler()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
file.createNewFile();
|
||||||
|
try ( FileReader rd = new FileReader( file ) )
|
||||||
|
{
|
||||||
|
data = yaml.loadAs( rd, Map.class );
|
||||||
|
}
|
||||||
|
} catch ( YAMLException ex )
|
||||||
|
{
|
||||||
|
file.renameTo( new File( "locations.yml.old" ) );
|
||||||
|
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not load reconnect locations, resetting them" );
|
||||||
|
} catch ( IOException ex )
|
||||||
|
{
|
||||||
|
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not load reconnect locations", ex );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( data == null )
|
||||||
|
{
|
||||||
|
data = new HashMap<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ServerInfo getStoredServer(ProxiedPlayer player)
|
||||||
|
{
|
||||||
|
ServerInfo server = null;
|
||||||
|
lock.readLock().lock();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
server = ProxyServer.getInstance().getServerInfo( data.get( key( player ) ) );
|
||||||
|
} finally
|
||||||
|
{
|
||||||
|
lock.readLock().unlock();
|
||||||
|
}
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setServer(ProxiedPlayer player)
|
||||||
|
{
|
||||||
|
lock.writeLock().lock();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
data.put( key( player ), ( player.getReconnectServer() != null ) ? player.getReconnectServer().getName() : player.getServer().getInfo().getName() );
|
||||||
|
} finally
|
||||||
|
{
|
||||||
|
lock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String key(ProxiedPlayer player)
|
||||||
|
{
|
||||||
|
InetSocketAddress host = player.getPendingConnection().getVirtualHost();
|
||||||
|
return player.getName() + ";" + host.getHostString() + ":" + host.getPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save()
|
||||||
|
{
|
||||||
|
Map<String, String> copy = new HashMap<>();
|
||||||
|
lock.readLock().lock();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
copy.putAll( data );
|
||||||
|
} finally
|
||||||
|
{
|
||||||
|
lock.readLock().unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
try ( FileWriter wr = new FileWriter( file ) )
|
||||||
|
{
|
||||||
|
yaml.dump( copy, wr );
|
||||||
|
} catch ( IOException ex )
|
||||||
|
{
|
||||||
|
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not save reconnect locations", ex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@@ -4,14 +4,16 @@ import com.google.common.base.Preconditions;
|
|||||||
import com.google.common.collect.HashMultimap;
|
import com.google.common.collect.HashMultimap;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
import com.google.common.collect.Multimaps;
|
import com.google.common.collect.Multimaps;
|
||||||
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
import gnu.trove.TCollections;
|
import gnu.trove.TCollections;
|
||||||
import gnu.trove.map.TIntObjectMap;
|
import gnu.trove.map.TIntObjectMap;
|
||||||
import gnu.trove.map.hash.TIntObjectHashMap;
|
import gnu.trove.map.hash.TIntObjectHashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import net.md_5.bungee.BungeeCord;
|
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
import net.md_5.bungee.api.scheduler.ScheduledTask;
|
import net.md_5.bungee.api.scheduler.ScheduledTask;
|
||||||
import net.md_5.bungee.api.scheduler.TaskScheduler;
|
import net.md_5.bungee.api.scheduler.TaskScheduler;
|
||||||
@@ -19,16 +21,22 @@ import net.md_5.bungee.api.scheduler.TaskScheduler;
|
|||||||
public class BungeeScheduler implements TaskScheduler
|
public class BungeeScheduler implements TaskScheduler
|
||||||
{
|
{
|
||||||
|
|
||||||
|
private final ExecutorService s = Executors.newCachedThreadPool( new ThreadFactoryBuilder().setNameFormat( "Bungee Pool Thread #%1$d" ).build() );
|
||||||
private final AtomicInteger taskCounter = new AtomicInteger();
|
private final AtomicInteger taskCounter = new AtomicInteger();
|
||||||
private final TIntObjectMap<BungeeTask> tasks = TCollections.synchronizedMap( new TIntObjectHashMap<BungeeTask>() );
|
private final TIntObjectMap<BungeeTask> tasks = TCollections.synchronizedMap( new TIntObjectHashMap<BungeeTask>() );
|
||||||
private final Multimap<Plugin, BungeeTask> tasksByPlugin = Multimaps.synchronizedMultimap( HashMultimap.<Plugin, BungeeTask>create() );
|
private final Multimap<Plugin, BungeeTask> tasksByPlugin = Multimaps.synchronizedMultimap( HashMultimap.<Plugin, BungeeTask>create() );
|
||||||
|
|
||||||
|
public void shutdown()
|
||||||
|
{
|
||||||
|
s.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cancel(int id)
|
public void cancel(int id)
|
||||||
{
|
{
|
||||||
BungeeTask task = tasks.remove( id );
|
BungeeTask task = tasks.remove( id );
|
||||||
|
task.cancel();
|
||||||
tasksByPlugin.values().remove( task );
|
tasksByPlugin.values().remove( task );
|
||||||
task.getFuture().cancel( false );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -61,21 +69,17 @@ public class BungeeScheduler implements TaskScheduler
|
|||||||
@Override
|
@Override
|
||||||
public ScheduledTask schedule(Plugin owner, Runnable task, long delay, TimeUnit unit)
|
public ScheduledTask schedule(Plugin owner, Runnable task, long delay, TimeUnit unit)
|
||||||
{
|
{
|
||||||
return prepare( owner, task ).setFuture( BungeeCord.getInstance().executors.schedule( task, delay, unit ) );
|
return schedule( owner, task, delay, 0, unit );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ScheduledTask schedule(Plugin owner, Runnable task, long delay, long period, TimeUnit unit)
|
public ScheduledTask schedule(Plugin owner, Runnable task, long delay, long period, TimeUnit unit)
|
||||||
{
|
|
||||||
return prepare( owner, task ).setFuture( BungeeCord.getInstance().executors.scheduleWithFixedDelay( task, delay, period, unit ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
private BungeeTask prepare(Plugin owner, Runnable task)
|
|
||||||
{
|
{
|
||||||
Preconditions.checkNotNull( owner, "owner" );
|
Preconditions.checkNotNull( owner, "owner" );
|
||||||
Preconditions.checkNotNull( task, "task" );
|
Preconditions.checkNotNull( task, "task" );
|
||||||
BungeeTask prepared = new BungeeTask( taskCounter.getAndIncrement(), owner, task );
|
BungeeTask prepared = new BungeeTask( this, taskCounter.getAndIncrement(), owner, task, delay, period, unit );
|
||||||
tasks.put( prepared.getId(), prepared );
|
tasks.put( prepared.getId(), prepared );
|
||||||
|
s.execute( prepared );
|
||||||
return prepared;
|
return prepared;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,32 +1,81 @@
|
|||||||
package net.md_5.bungee.scheduler;
|
package net.md_5.bungee.scheduler;
|
||||||
|
|
||||||
import java.util.concurrent.ScheduledFuture;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import lombok.AccessLevel;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.logging.Level;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.Setter;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
import net.md_5.bungee.api.scheduler.ScheduledTask;
|
import net.md_5.bungee.api.scheduler.ScheduledTask;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class BungeeTask implements ScheduledTask
|
public class BungeeTask implements Runnable, ScheduledTask
|
||||||
{
|
{
|
||||||
|
|
||||||
|
private final BungeeScheduler sched;
|
||||||
private final int id;
|
private final int id;
|
||||||
private final Plugin owner;
|
private final Plugin owner;
|
||||||
private final Runnable task;
|
private final Runnable task;
|
||||||
@Setter(AccessLevel.NONE)
|
//
|
||||||
private ScheduledFuture<?> future;
|
private final long delay;
|
||||||
|
private final long period;
|
||||||
|
private final AtomicBoolean running = new AtomicBoolean( true );
|
||||||
|
|
||||||
|
public BungeeTask(BungeeScheduler sched, int id, Plugin owner, Runnable task, long delay, long period, TimeUnit unit)
|
||||||
|
{
|
||||||
|
this.sched = sched;
|
||||||
|
this.id = id;
|
||||||
|
this.owner = owner;
|
||||||
|
this.task = task;
|
||||||
|
this.delay = unit.toMillis( delay );
|
||||||
|
this.period = unit.toMillis( period );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getDelay(TimeUnit unit)
|
public void cancel()
|
||||||
{
|
{
|
||||||
return future.getDelay( unit );
|
running.set( false );
|
||||||
}
|
}
|
||||||
|
|
||||||
BungeeTask setFuture(ScheduledFuture<?> future)
|
@Override
|
||||||
|
public void run()
|
||||||
{
|
{
|
||||||
this.future = future;
|
if ( delay > 0 )
|
||||||
return this;
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep( delay );
|
||||||
|
} catch ( InterruptedException ex )
|
||||||
|
{
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( running.get() )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
task.run();
|
||||||
|
} catch ( Throwable t )
|
||||||
|
{
|
||||||
|
ProxyServer.getInstance().getLogger().log( Level.SEVERE, String.format( "Task %s encountered an exception", this ), t );
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a period of 0 or less, only run once
|
||||||
|
if ( period <= 0 )
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep( period );
|
||||||
|
} catch ( InterruptedException ex )
|
||||||
|
{
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sched.cancel( this );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,28 +0,0 @@
|
|||||||
package net.md_5.bungee.scheduler;
|
|
||||||
|
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
|
||||||
import java.util.concurrent.ThreadFactory;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
|
||||||
|
|
||||||
public class BungeeThreadPool extends ScheduledThreadPoolExecutor
|
|
||||||
{
|
|
||||||
|
|
||||||
public BungeeThreadPool(ThreadFactory threadFactory)
|
|
||||||
{
|
|
||||||
super( Integer.MAX_VALUE, threadFactory );
|
|
||||||
setKeepAliveTime( 5, TimeUnit.MINUTES );
|
|
||||||
allowCoreThreadTimeOut( true );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void afterExecute(Runnable r, Throwable t)
|
|
||||||
{
|
|
||||||
super.afterExecute( r, t );
|
|
||||||
if ( t != null )
|
|
||||||
{
|
|
||||||
ProxyServer.getInstance().getLogger().log( Level.SEVERE, "Task caused exception whilst running", t );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,5 +1,6 @@
|
|||||||
alert: \u00a78[\u00a74Alert\u00a78]\u00a7r
|
alert: \u00a78[\u00a74Alert\u00a78]\u00a7r
|
||||||
already_connected: You are already connected to the server
|
already_connected: \u00a7cYou are already connected to this server
|
||||||
|
already_connecting: \u00a7cAlready connecting to this server!
|
||||||
connect_kick: \u00a7cKicked whilst connecting to
|
connect_kick: \u00a7cKicked whilst connecting to
|
||||||
current_server: \u00a76You are currently connected to
|
current_server: \u00a76You are currently connected to
|
||||||
fallback_kick: \u00a7cCould not connect to default server, please try again later:
|
fallback_kick: \u00a7cCould not connect to default server, please try again later:
|
||||||
@@ -9,8 +10,11 @@ mojang_fail: Error occurred while contacting login servers, are they down?
|
|||||||
no_permission: \u00a7cYou do not have permission to execute this command!
|
no_permission: \u00a7cYou do not have permission to execute this command!
|
||||||
no_server: \u00a7cThe specified server does not exist
|
no_server: \u00a7cThe specified server does not exist
|
||||||
no_server_permission: \u00a7cYou don't have permission to access this server
|
no_server_permission: \u00a7cYou don't have permission to access this server
|
||||||
|
outdated_client: Outdated Client!
|
||||||
|
outdated_server: Outdated Server!
|
||||||
proxy_full: Server is full
|
proxy_full: Server is full
|
||||||
restart: [Proxy] Proxy restarting.
|
restart: [Proxy] Proxy restarting.
|
||||||
server_kick: [Kicked]
|
server_kick: [Kicked]
|
||||||
server_list: \u00a76You may connect to the following servers at this time:
|
server_list: \u00a76You may connect to the following servers at this time:
|
||||||
|
server_went_down: \u00a7cThe server you were previously on went down, you have been connected to the lobby
|
||||||
total_players: Total players online:
|
total_players: Total players online:
|
||||||
|
26
proxy/src/test/java/net/md_5/bungee/ThrottleTest.java
Normal file
26
proxy/src/test/java/net/md_5/bungee/ThrottleTest.java
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package net.md_5.bungee;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class ThrottleTest
|
||||||
|
{
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testThrottle() throws InterruptedException, UnknownHostException
|
||||||
|
{
|
||||||
|
ConnectionThrottle throttle = new ConnectionThrottle( 5 );
|
||||||
|
InetAddress address = InetAddress.getLocalHost();
|
||||||
|
|
||||||
|
Assert.assertFalse( "Address should not be throttled", throttle.throttle( address ) );
|
||||||
|
Assert.assertTrue( "Address should be throttled", throttle.throttle( address ) );
|
||||||
|
|
||||||
|
throttle.unthrottle( address );
|
||||||
|
Assert.assertFalse( "Address should not be throttled", throttle.throttle( address ) );
|
||||||
|
|
||||||
|
Thread.sleep( 15 );
|
||||||
|
Assert.assertFalse( "Address should not be throttled", throttle.throttle( address ) );
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user