mirror of
https://github.com/SpigotMC/BungeeCord.git
synced 2024-09-28 05:37:28 +02:00
Merge branch 'master' of https://github.com/SpigotMC/BungeeCord into patch/bossbar
This commit is contained in:
commit
ad1ef316a3
21
.github/workflows/maven.yml
vendored
Normal file
21
.github/workflows/maven.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
name: Maven Build
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
java: [8, 11]
|
||||
|
||||
name: Java ${{ matrix.java }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: ${{ matrix.java }}
|
||||
- run: java -version && mvn --version
|
||||
- run: mvn --activate-profiles dist --no-transfer-progress package
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -24,7 +24,7 @@ dist/
|
||||
manifest.mf
|
||||
|
||||
# Mac filesystem dust
|
||||
.DS_Store/
|
||||
.DS_Store
|
||||
|
||||
# intellij
|
||||
*.iml
|
||||
|
@ -1,8 +0,0 @@
|
||||
sudo: false
|
||||
language: java
|
||||
jdk:
|
||||
- openjdk7
|
||||
- oraclejdk7
|
||||
- oraclejdk8
|
||||
notifications:
|
||||
email: false
|
@ -23,4 +23,4 @@ Binaries
|
||||
--------
|
||||
Precompiled binaries are available for end users on [Jenkins](https://www.spigotmc.org/go/bungeecord-dl).
|
||||
|
||||
(c) 2012-2018 SpigotMC Pty. Ltd.
|
||||
(c) 2012-2020 SpigotMC Pty. Ltd.
|
||||
|
16
api/pom.xml
16
api/pom.xml
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-API</name>
|
||||
@ -43,5 +43,17 @@
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-transport-native-unix-common</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>1.25</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
@ -2,7 +2,9 @@ package net.md_5.bungee;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.primitives.UnsignedLongs;
|
||||
import io.netty.channel.unix.DomainSocketAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.UUID;
|
||||
@ -21,15 +23,30 @@ public class Util
|
||||
* @param hostline in the format of 'host:port'
|
||||
* @return the constructed hostname + port.
|
||||
*/
|
||||
public static InetSocketAddress getAddr(String hostline)
|
||||
public static SocketAddress getAddr(String hostline)
|
||||
{
|
||||
URI uri;
|
||||
URI uri = null;
|
||||
try
|
||||
{
|
||||
uri = new URI( "tcp://" + hostline );
|
||||
uri = new URI( hostline );
|
||||
} catch ( URISyntaxException ex )
|
||||
{
|
||||
throw new IllegalArgumentException( "Bad hostline: " + hostline, ex );
|
||||
}
|
||||
|
||||
if ( uri != null && "unix".equals( uri.getScheme() ) )
|
||||
{
|
||||
return new DomainSocketAddress( uri.getPath() );
|
||||
}
|
||||
|
||||
if ( uri == null || uri.getHost() == null )
|
||||
{
|
||||
try
|
||||
{
|
||||
uri = new URI( "tcp://" + hostline );
|
||||
} catch ( URISyntaxException ex )
|
||||
{
|
||||
throw new IllegalArgumentException( "Bad hostline: " + hostline, ex );
|
||||
}
|
||||
}
|
||||
|
||||
if ( uri.getHost() == null )
|
||||
|
@ -16,52 +16,96 @@ public interface ProxyConfig
|
||||
|
||||
/**
|
||||
* Time before users are disconnected due to no network activity.
|
||||
*
|
||||
* @return timeout
|
||||
*/
|
||||
int getTimeout();
|
||||
|
||||
/**
|
||||
* UUID used for metrics.
|
||||
*
|
||||
* @return uuid
|
||||
*/
|
||||
String getUuid();
|
||||
|
||||
/**
|
||||
* Set of all listeners.
|
||||
*
|
||||
* @return listeners
|
||||
*/
|
||||
Collection<ListenerInfo> getListeners();
|
||||
|
||||
/**
|
||||
* Set of all servers.
|
||||
*
|
||||
* @return servers
|
||||
*/
|
||||
Map<String, ServerInfo> getServers();
|
||||
|
||||
/**
|
||||
* Does the server authenticate with mojang
|
||||
* Does the server authenticate with Mojang.
|
||||
*
|
||||
* @return online mode
|
||||
*/
|
||||
boolean isOnlineMode();
|
||||
|
||||
/**
|
||||
* Whether proxy commands are logged to the proxy log
|
||||
* Whether proxy commands are logged to the proxy log.
|
||||
*
|
||||
* @return log commands
|
||||
*/
|
||||
boolean isLogCommands();
|
||||
|
||||
/**
|
||||
* Time in milliseconds to cache server list info from a ping request from
|
||||
* the proxy to a server.
|
||||
*
|
||||
* @return cache time
|
||||
*/
|
||||
int getRemotePingCache();
|
||||
|
||||
/**
|
||||
* Returns the player max.
|
||||
*
|
||||
* @return player limit
|
||||
*/
|
||||
int getPlayerLimit();
|
||||
|
||||
/**
|
||||
* A collection of disabled commands.
|
||||
*
|
||||
* @return disabled commands
|
||||
*/
|
||||
Collection<String> getDisabledCommands();
|
||||
|
||||
/**
|
||||
* Time in milliseconds before timing out a clients request to connect to a
|
||||
* server.
|
||||
*
|
||||
* @return connect timeout
|
||||
*/
|
||||
int getServerConnectTimeout();
|
||||
|
||||
/**
|
||||
* Time in milliseconds before timing out a ping request from the proxy to a
|
||||
* server when attempting to request server list info.
|
||||
*
|
||||
* @return ping timeout
|
||||
*/
|
||||
int getRemotePingTimeout();
|
||||
|
||||
/**
|
||||
* The connection throttle delay.
|
||||
*
|
||||
* @return throttle
|
||||
*/
|
||||
@Deprecated
|
||||
int getThrottle();
|
||||
|
||||
/**
|
||||
* Whether the proxy will parse IPs with spigot or not
|
||||
* Whether the proxy will parse IPs with spigot or not.
|
||||
*
|
||||
* @return ip forward
|
||||
*/
|
||||
@Deprecated
|
||||
boolean isIpForward();
|
||||
@ -69,6 +113,7 @@ public interface ProxyConfig
|
||||
/**
|
||||
* The encoded favicon.
|
||||
*
|
||||
* @return favicon
|
||||
* @deprecated Use #getFaviconObject instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@ -76,6 +121,8 @@ public interface ProxyConfig
|
||||
|
||||
/**
|
||||
* The favicon used for the server ping list.
|
||||
*
|
||||
* @return favicon
|
||||
*/
|
||||
Favicon getFaviconObject();
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package net.md_5.bungee.api;
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.io.File;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
@ -55,6 +56,8 @@ public abstract class ProxyServer
|
||||
/**
|
||||
* Gets a localized string from the .properties file.
|
||||
*
|
||||
* @param name translation name
|
||||
* @param args translation arguments
|
||||
* @return the localized string
|
||||
*/
|
||||
public abstract String getTranslation(String name, Object... args);
|
||||
@ -207,6 +210,18 @@ public abstract class ProxyServer
|
||||
*/
|
||||
public abstract ServerInfo constructServerInfo(String name, InetSocketAddress address, String motd, boolean restricted);
|
||||
|
||||
/**
|
||||
* Factory method to construct an implementation specific server info
|
||||
* instance.
|
||||
*
|
||||
* @param name name 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
|
||||
* @return the constructed instance
|
||||
*/
|
||||
public abstract ServerInfo constructServerInfo(String name, SocketAddress address, String motd, boolean restricted);
|
||||
|
||||
/**
|
||||
* Returns the console overlord for this proxy. Being the console, this
|
||||
* command server cannot have permissions or groups, and will be able to
|
||||
|
@ -3,6 +3,7 @@ package net.md_5.bungee.api;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.Setter;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.event.ServerConnectEvent;
|
||||
|
||||
@ -59,12 +60,14 @@ public class ServerConnectRequest
|
||||
/**
|
||||
* Timeout in milliseconds for request.
|
||||
*/
|
||||
private final int connectTimeout;
|
||||
@Setter
|
||||
private int connectTimeout;
|
||||
/**
|
||||
* Should the player be attempted to connect to the next server in their
|
||||
* queue if the initial request fails.
|
||||
*/
|
||||
private final boolean retry;
|
||||
@Setter
|
||||
private boolean retry;
|
||||
|
||||
/**
|
||||
* Class that sets default properties/adds methods to the lombok builder
|
||||
@ -73,6 +76,6 @@ public class ServerConnectRequest
|
||||
public static class Builder
|
||||
{
|
||||
|
||||
private int connectTimeout = 5000; // TODO: Configurable
|
||||
private int connectTimeout = ProxyServer.getInstance().getConfig().getServerConnectTimeout();
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.md_5.bungee.api.config;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
@ -18,7 +19,7 @@ public class ListenerInfo
|
||||
/**
|
||||
* Host to bind to.
|
||||
*/
|
||||
private final InetSocketAddress host;
|
||||
private final SocketAddress socketAddress;
|
||||
/**
|
||||
* Displayed MOTD.
|
||||
*/
|
||||
@ -102,4 +103,16 @@ public class ListenerInfo
|
||||
{
|
||||
return ( serverPriority.size() > 1 ) ? serverPriority.get( 1 ) : getDefaultServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the bind address as an InetSocketAddress if possible.
|
||||
*
|
||||
* @return bind host
|
||||
* @deprecated BungeeCord can listen via Unix domain sockets
|
||||
*/
|
||||
@Deprecated
|
||||
public InetSocketAddress getHost()
|
||||
{
|
||||
return (InetSocketAddress) socketAddress;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.md_5.bungee.api.config;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Collection;
|
||||
import net.md_5.bungee.api.Callback;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
@ -26,9 +27,19 @@ public interface ServerInfo
|
||||
* class.
|
||||
*
|
||||
* @return the IP and port pair for this server
|
||||
* @deprecated BungeeCord can connect via Unix domain sockets
|
||||
*/
|
||||
@Deprecated
|
||||
InetSocketAddress getAddress();
|
||||
|
||||
/**
|
||||
* Gets the connectable address for this server. Implementations expect this
|
||||
* to be used as the unique identifier per each instance of this class.
|
||||
*
|
||||
* @return the address for this server
|
||||
*/
|
||||
SocketAddress getSocketAddress();
|
||||
|
||||
/**
|
||||
* Get the set of all players on this server.
|
||||
*
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.md_5.bungee.api.connection;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.protocol.DefinedPacket;
|
||||
|
||||
@ -16,9 +17,18 @@ public interface Connection
|
||||
* Gets the remote address of this connection.
|
||||
*
|
||||
* @return the remote address
|
||||
* @deprecated BungeeCord can accept connections via Unix domain sockets
|
||||
*/
|
||||
@Deprecated
|
||||
InetSocketAddress getAddress();
|
||||
|
||||
/**
|
||||
* Gets the remote address of this connection.
|
||||
*
|
||||
* @return the remote address
|
||||
*/
|
||||
SocketAddress getSocketAddress();
|
||||
|
||||
/**
|
||||
* Disconnects this end of the connection for the specified reason. If this
|
||||
* is an {@link ProxiedPlayer} the respective server connection will be
|
||||
|
@ -0,0 +1,35 @@
|
||||
package net.md_5.bungee.api.event;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
import net.md_5.bungee.api.plugin.Cancellable;
|
||||
import net.md_5.bungee.api.plugin.Event;
|
||||
|
||||
/**
|
||||
* Event called to represent an initial client connection.
|
||||
* <br>
|
||||
* Note: This event is called at an early stage of every connection, handling
|
||||
* should be <b>fast</b>.
|
||||
*/
|
||||
@Data
|
||||
@ToString(callSuper = false)
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class ClientConnectEvent extends Event implements Cancellable
|
||||
{
|
||||
|
||||
/**
|
||||
* Cancelled state.
|
||||
*/
|
||||
private boolean cancelled;
|
||||
/**
|
||||
* Remote address of connection.
|
||||
*/
|
||||
private final SocketAddress socketAddress;
|
||||
/**
|
||||
* Listener that accepted the connection.
|
||||
*/
|
||||
private final ListenerInfo listener;
|
||||
}
|
@ -4,6 +4,7 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import net.md_5.bungee.api.ServerConnectRequest;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.plugin.Cancellable;
|
||||
@ -30,11 +31,18 @@ public class ServerConnectEvent extends Event implements Cancellable
|
||||
*/
|
||||
@NonNull
|
||||
private ServerInfo target;
|
||||
/**
|
||||
* Reason for connecting to a new server.
|
||||
*/
|
||||
private final Reason reason;
|
||||
/**
|
||||
* Request used to connect to given server.
|
||||
*/
|
||||
private final ServerConnectRequest request;
|
||||
/**
|
||||
* Cancelled state.
|
||||
*/
|
||||
private boolean cancelled;
|
||||
private final Reason reason;
|
||||
|
||||
@Deprecated
|
||||
public ServerConnectEvent(ProxiedPlayer player, ServerInfo target)
|
||||
@ -42,11 +50,18 @@ public class ServerConnectEvent extends Event implements Cancellable
|
||||
this( player, target, Reason.UNKNOWN );
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public ServerConnectEvent(ProxiedPlayer player, ServerInfo target, Reason reason)
|
||||
{
|
||||
this( player, target, reason, null );
|
||||
}
|
||||
|
||||
public ServerConnectEvent(ProxiedPlayer player, ServerInfo target, Reason reason, ServerConnectRequest request)
|
||||
{
|
||||
this.player = player;
|
||||
this.target = target;
|
||||
this.reason = reason;
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public enum Reason
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.md_5.bungee.api.plugin;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
@ -27,6 +28,22 @@ public class Plugin
|
||||
@Getter
|
||||
private Logger logger;
|
||||
|
||||
public Plugin()
|
||||
{
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
Preconditions.checkState( classLoader instanceof PluginClassloader, "Plugin requires " + PluginClassloader.class.getName() );
|
||||
|
||||
( (PluginClassloader) classLoader ).init( this );
|
||||
}
|
||||
|
||||
protected Plugin(ProxyServer proxy, PluginDescription description)
|
||||
{
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
Preconditions.checkState( !( classLoader instanceof PluginClassloader ), "Cannot use initialization constructor at runtime" );
|
||||
|
||||
// init( proxy, description );
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the plugin has just been loaded. Most of the proxy will not
|
||||
* be initialized, so only use it for registering
|
||||
|
@ -1,23 +1,33 @@
|
||||
package net.md_5.bungee.api.plugin;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
|
||||
public class PluginClassloader extends URLClassLoader
|
||||
final class PluginClassloader extends URLClassLoader
|
||||
{
|
||||
|
||||
private static final Set<PluginClassloader> allLoaders = new CopyOnWriteArraySet<>();
|
||||
//
|
||||
private final ProxyServer proxy;
|
||||
private final PluginDescription desc;
|
||||
//
|
||||
private Plugin plugin;
|
||||
|
||||
static
|
||||
{
|
||||
ClassLoader.registerAsParallelCapable();
|
||||
}
|
||||
|
||||
public PluginClassloader(URL[] urls)
|
||||
public PluginClassloader(ProxyServer proxy, PluginDescription desc, URL[] urls)
|
||||
{
|
||||
super( urls );
|
||||
this.proxy = proxy;
|
||||
this.desc = desc;
|
||||
|
||||
allLoaders.add( this );
|
||||
}
|
||||
|
||||
@ -52,4 +62,17 @@ public class PluginClassloader extends URLClassLoader
|
||||
}
|
||||
throw new ClassNotFoundException( name );
|
||||
}
|
||||
|
||||
void init(Plugin plugin)
|
||||
{
|
||||
Preconditions.checkArgument( plugin != null, "plugin" );
|
||||
Preconditions.checkArgument( plugin.getClass().getClassLoader() == this, "Plugin has incorrect ClassLoader" );
|
||||
if ( this.plugin != null )
|
||||
{
|
||||
throw new IllegalArgumentException( "Plugin already initialized!" );
|
||||
}
|
||||
|
||||
this.plugin = plugin;
|
||||
plugin.init( proxy, desc );
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ import org.yaml.snakeyaml.introspector.PropertyUtils;
|
||||
* example event handling and plugin management.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class PluginManager
|
||||
public final class PluginManager
|
||||
{
|
||||
|
||||
/*========================================================================*/
|
||||
@ -148,6 +148,9 @@ public class PluginManager
|
||||
* @param sender the sender executing the command
|
||||
* @param commandLine the complete command line including command name and
|
||||
* arguments
|
||||
* @param tabResults list to place tab results into. If this list is non
|
||||
* null then the command will not be executed and tab results will be
|
||||
* returned instead.
|
||||
* @return whether the command was handled
|
||||
*/
|
||||
public boolean dispatchCommand(CommandSender sender, String commandLine, List<String> tabResults)
|
||||
@ -317,14 +320,13 @@ public class PluginManager
|
||||
{
|
||||
try
|
||||
{
|
||||
URLClassLoader loader = new PluginClassloader( new URL[]
|
||||
URLClassLoader loader = new PluginClassloader( proxy, plugin, new URL[]
|
||||
{
|
||||
plugin.getFile().toURI().toURL()
|
||||
} );
|
||||
Class<?> main = loader.loadClass( plugin.getMain() );
|
||||
Plugin clazz = (Plugin) main.getDeclaredConstructor().newInstance();
|
||||
|
||||
clazz.init( proxy, plugin );
|
||||
plugins.put( plugin.getName(), clazz );
|
||||
clazz.onLoad();
|
||||
ProxyServer.getInstance().getLogger().log( Level.INFO, "Loaded plugin {0} version {1} by {2}", new Object[]
|
||||
@ -400,9 +402,9 @@ public class PluginManager
|
||||
long elapsed = System.nanoTime() - start;
|
||||
if ( elapsed > 250000000 )
|
||||
{
|
||||
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Event {0} took {1}ns to process!", new Object[]
|
||||
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Event {0} took {1}ms to process!", new Object[]
|
||||
{
|
||||
event, elapsed
|
||||
event, elapsed / 1000000
|
||||
} );
|
||||
}
|
||||
return event;
|
||||
@ -440,6 +442,8 @@ public class PluginManager
|
||||
|
||||
/**
|
||||
* Unregister all of a Plugin's listener.
|
||||
*
|
||||
* @param plugin target plugin
|
||||
*/
|
||||
public void unregisterListeners(Plugin plugin)
|
||||
{
|
||||
|
@ -86,6 +86,7 @@ public interface TaskScheduler
|
||||
/**
|
||||
* An executor service which underlies this scheduler.
|
||||
*
|
||||
* @param plugin owning plugin
|
||||
* @return the underlying executor service or compatible wrapper
|
||||
*/
|
||||
ExecutorService getExecutorService(Plugin plugin);
|
||||
|
@ -1,11 +1,11 @@
|
||||
package net.md_5.bungee.api;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Collection;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.ServerConnectEvent;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ServerConnectRequestTest
|
||||
@ -19,6 +19,12 @@ public class ServerConnectRequestTest
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getSocketAddress()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getAddress()
|
||||
{
|
||||
@ -72,13 +78,6 @@ public class ServerConnectRequestTest
|
||||
}
|
||||
};
|
||||
|
||||
@Test
|
||||
public void testDefaultConnectTimeout()
|
||||
{
|
||||
ServerConnectRequest request = ServerConnectRequest.builder().target( DUMMY_INFO ).reason( ServerConnectEvent.Reason.JOIN_PROXY ).build();
|
||||
Assert.assertEquals( 5000, request.getConnectTimeout() );
|
||||
}
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void testNullTarget()
|
||||
{
|
||||
|
@ -1,6 +1,8 @@
|
||||
package net.md_5.bungee.util;
|
||||
|
||||
import io.netty.channel.unix.DomainSocketAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -44,6 +46,9 @@ public class AddressParseTest
|
||||
},
|
||||
{
|
||||
"[0:0:0:0:0:0:0:1]:1337", "0:0:0:0:0:0:0:1", 1337
|
||||
},
|
||||
{
|
||||
"unix:///var/run/bungee.sock", "/var/run/bungee.sock", -1
|
||||
}
|
||||
} );
|
||||
}
|
||||
@ -54,8 +59,23 @@ public class AddressParseTest
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
InetSocketAddress parsed = Util.getAddr( line );
|
||||
Assert.assertEquals( host, parsed.getHostString() );
|
||||
Assert.assertEquals( port, parsed.getPort() );
|
||||
SocketAddress parsed = Util.getAddr( line );
|
||||
|
||||
if ( parsed instanceof InetSocketAddress )
|
||||
{
|
||||
InetSocketAddress tcp = (InetSocketAddress) parsed;
|
||||
|
||||
Assert.assertEquals( host, tcp.getHostString() );
|
||||
Assert.assertEquals( port, tcp.getPort() );
|
||||
} else if ( parsed instanceof DomainSocketAddress )
|
||||
{
|
||||
DomainSocketAddress unix = (DomainSocketAddress) parsed;
|
||||
|
||||
Assert.assertEquals( host, unix.path() );
|
||||
Assert.assertEquals( -1, port );
|
||||
} else
|
||||
{
|
||||
throw new AssertionError( "Unknown socket " + parsed );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-bootstrap</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-Bootstrap</name>
|
||||
@ -20,6 +20,7 @@
|
||||
|
||||
<properties>
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
<maven.javadoc.skip>true</maven.javadoc.skip>
|
||||
<maven.compiler.source>1.6</maven.compiler.source>
|
||||
<maven.compiler.target>1.6</maven.compiler.target>
|
||||
<maven.build.timestamp.format>yyyyMMdd</maven.build.timestamp.format>
|
||||
@ -40,7 +41,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
<version>3.2.0</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
@ -54,7 +55,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.2.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-chat</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-Chat</name>
|
||||
|
@ -1,145 +1,180 @@
|
||||
package net.md_5.bungee.api;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.awt.Color;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Simplistic enumeration of all supported color values for chat.
|
||||
*/
|
||||
public enum ChatColor
|
||||
public final class ChatColor
|
||||
{
|
||||
|
||||
/**
|
||||
* Represents black.
|
||||
*/
|
||||
BLACK( '0', "black" ),
|
||||
/**
|
||||
* Represents dark blue.
|
||||
*/
|
||||
DARK_BLUE( '1', "dark_blue" ),
|
||||
/**
|
||||
* Represents dark green.
|
||||
*/
|
||||
DARK_GREEN( '2', "dark_green" ),
|
||||
/**
|
||||
* Represents dark blue (aqua).
|
||||
*/
|
||||
DARK_AQUA( '3', "dark_aqua" ),
|
||||
/**
|
||||
* Represents dark red.
|
||||
*/
|
||||
DARK_RED( '4', "dark_red" ),
|
||||
/**
|
||||
* Represents dark purple.
|
||||
*/
|
||||
DARK_PURPLE( '5', "dark_purple" ),
|
||||
/**
|
||||
* Represents gold.
|
||||
*/
|
||||
GOLD( '6', "gold" ),
|
||||
/**
|
||||
* Represents gray.
|
||||
*/
|
||||
GRAY( '7', "gray" ),
|
||||
/**
|
||||
* Represents dark gray.
|
||||
*/
|
||||
DARK_GRAY( '8', "dark_gray" ),
|
||||
/**
|
||||
* Represents blue.
|
||||
*/
|
||||
BLUE( '9', "blue" ),
|
||||
/**
|
||||
* Represents green.
|
||||
*/
|
||||
GREEN( 'a', "green" ),
|
||||
/**
|
||||
* Represents aqua.
|
||||
*/
|
||||
AQUA( 'b', "aqua" ),
|
||||
/**
|
||||
* Represents red.
|
||||
*/
|
||||
RED( 'c', "red" ),
|
||||
/**
|
||||
* Represents light purple.
|
||||
*/
|
||||
LIGHT_PURPLE( 'd', "light_purple" ),
|
||||
/**
|
||||
* Represents yellow.
|
||||
*/
|
||||
YELLOW( 'e', "yellow" ),
|
||||
/**
|
||||
* Represents white.
|
||||
*/
|
||||
WHITE( 'f', "white" ),
|
||||
/**
|
||||
* Represents magical characters that change around randomly.
|
||||
*/
|
||||
MAGIC( 'k', "obfuscated" ),
|
||||
/**
|
||||
* Makes the text bold.
|
||||
*/
|
||||
BOLD( 'l', "bold" ),
|
||||
/**
|
||||
* Makes a line appear through the text.
|
||||
*/
|
||||
STRIKETHROUGH( 'm', "strikethrough" ),
|
||||
/**
|
||||
* Makes the text appear underlined.
|
||||
*/
|
||||
UNDERLINE( 'n', "underline" ),
|
||||
/**
|
||||
* Makes the text italic.
|
||||
*/
|
||||
ITALIC( 'o', "italic" ),
|
||||
/**
|
||||
* Resets all previous chat colors or formats.
|
||||
*/
|
||||
RESET( 'r', "reset" );
|
||||
/**
|
||||
* The special character which prefixes all chat colour codes. Use this if
|
||||
* you need to dynamically convert colour codes from your custom format.
|
||||
*/
|
||||
public static final char COLOR_CHAR = '\u00A7';
|
||||
public static final String ALL_CODES = "0123456789AaBbCcDdEeFfKkLlMmNnOoRr";
|
||||
public static final String ALL_CODES = "0123456789AaBbCcDdEeFfKkLlMmNnOoRrXx";
|
||||
/**
|
||||
* Pattern to remove all colour codes.
|
||||
*/
|
||||
public static final Pattern STRIP_COLOR_PATTERN = Pattern.compile( "(?i)" + String.valueOf( COLOR_CHAR ) + "[0-9A-FK-OR]" );
|
||||
public static final Pattern STRIP_COLOR_PATTERN = Pattern.compile( "(?i)" + String.valueOf( COLOR_CHAR ) + "[0-9A-FK-ORX]" );
|
||||
/**
|
||||
* Colour instances keyed by their active character.
|
||||
*/
|
||||
private static final Map<Character, ChatColor> BY_CHAR = new HashMap<Character, ChatColor>();
|
||||
/**
|
||||
* The code appended to {@link #COLOR_CHAR} to make usable colour.
|
||||
* Colour instances keyed by their name.
|
||||
*/
|
||||
private final char code;
|
||||
private static final Map<String, ChatColor> BY_NAME = new HashMap<String, ChatColor>();
|
||||
/**
|
||||
* Represents black.
|
||||
*/
|
||||
public static final ChatColor BLACK = new ChatColor( '0', "black" );
|
||||
/**
|
||||
* Represents dark blue.
|
||||
*/
|
||||
public static final ChatColor DARK_BLUE = new ChatColor( '1', "dark_blue" );
|
||||
/**
|
||||
* Represents dark green.
|
||||
*/
|
||||
public static final ChatColor DARK_GREEN = new ChatColor( '2', "dark_green" );
|
||||
/**
|
||||
* Represents dark blue (aqua).
|
||||
*/
|
||||
public static final ChatColor DARK_AQUA = new ChatColor( '3', "dark_aqua" );
|
||||
/**
|
||||
* Represents dark red.
|
||||
*/
|
||||
public static final ChatColor DARK_RED = new ChatColor( '4', "dark_red" );
|
||||
/**
|
||||
* Represents dark purple.
|
||||
*/
|
||||
public static final ChatColor DARK_PURPLE = new ChatColor( '5', "dark_purple" );
|
||||
/**
|
||||
* Represents gold.
|
||||
*/
|
||||
public static final ChatColor GOLD = new ChatColor( '6', "gold" );
|
||||
/**
|
||||
* Represents gray.
|
||||
*/
|
||||
public static final ChatColor GRAY = new ChatColor( '7', "gray" );
|
||||
/**
|
||||
* Represents dark gray.
|
||||
*/
|
||||
public static final ChatColor DARK_GRAY = new ChatColor( '8', "dark_gray" );
|
||||
/**
|
||||
* Represents blue.
|
||||
*/
|
||||
public static final ChatColor BLUE = new ChatColor( '9', "blue" );
|
||||
/**
|
||||
* Represents green.
|
||||
*/
|
||||
public static final ChatColor GREEN = new ChatColor( 'a', "green" );
|
||||
/**
|
||||
* Represents aqua.
|
||||
*/
|
||||
public static final ChatColor AQUA = new ChatColor( 'b', "aqua" );
|
||||
/**
|
||||
* Represents red.
|
||||
*/
|
||||
public static final ChatColor RED = new ChatColor( 'c', "red" );
|
||||
/**
|
||||
* Represents light purple.
|
||||
*/
|
||||
public static final ChatColor LIGHT_PURPLE = new ChatColor( 'd', "light_purple" );
|
||||
/**
|
||||
* Represents yellow.
|
||||
*/
|
||||
public static final ChatColor YELLOW = new ChatColor( 'e', "yellow" );
|
||||
/**
|
||||
* Represents white.
|
||||
*/
|
||||
public static final ChatColor WHITE = new ChatColor( 'f', "white" );
|
||||
/**
|
||||
* Represents magical characters that change around randomly.
|
||||
*/
|
||||
public static final ChatColor MAGIC = new ChatColor( 'k', "obfuscated" );
|
||||
/**
|
||||
* Makes the text bold.
|
||||
*/
|
||||
public static final ChatColor BOLD = new ChatColor( 'l', "bold" );
|
||||
/**
|
||||
* Makes a line appear through the text.
|
||||
*/
|
||||
public static final ChatColor STRIKETHROUGH = new ChatColor( 'm', "strikethrough" );
|
||||
/**
|
||||
* Makes the text appear underlined.
|
||||
*/
|
||||
public static final ChatColor UNDERLINE = new ChatColor( 'n', "underline" );
|
||||
/**
|
||||
* Makes the text italic.
|
||||
*/
|
||||
public static final ChatColor ITALIC = new ChatColor( 'o', "italic" );
|
||||
/**
|
||||
* Resets all previous chat colors or formats.
|
||||
*/
|
||||
public static final ChatColor RESET = new ChatColor( 'r', "reset" );
|
||||
/**
|
||||
* Count used for populating legacy ordinal.
|
||||
*/
|
||||
private static int count = 0;
|
||||
/**
|
||||
* This colour's colour char prefixed by the {@link #COLOR_CHAR}.
|
||||
*/
|
||||
private final String toString;
|
||||
@Getter
|
||||
private final String name;
|
||||
|
||||
static
|
||||
{
|
||||
for ( ChatColor colour : values() )
|
||||
{
|
||||
BY_CHAR.put( colour.code, colour );
|
||||
}
|
||||
}
|
||||
private final int ordinal;
|
||||
|
||||
private ChatColor(char code, String name)
|
||||
{
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
this.toString = new String( new char[]
|
||||
{
|
||||
COLOR_CHAR, code
|
||||
} );
|
||||
this.ordinal = count++;
|
||||
|
||||
BY_CHAR.put( code, this );
|
||||
BY_NAME.put( name.toUpperCase( Locale.ROOT ), this );
|
||||
}
|
||||
|
||||
private ChatColor(String name, String toString)
|
||||
{
|
||||
this.name = name;
|
||||
this.toString = toString;
|
||||
this.ordinal = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
int hash = 7;
|
||||
hash = 53 * hash + Objects.hashCode( this.toString );
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if ( this == obj )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if ( obj == null || getClass() != obj.getClass() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
final ChatColor other = (ChatColor) obj;
|
||||
|
||||
return Objects.equals( this.toString, other.toString );
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -188,4 +223,95 @@ public enum ChatColor
|
||||
{
|
||||
return BY_CHAR.get( code );
|
||||
}
|
||||
|
||||
public static ChatColor of(Color color)
|
||||
{
|
||||
return of( "#" + Integer.toHexString( color.getRGB() ).substring( 2 ) );
|
||||
}
|
||||
|
||||
public static ChatColor of(String string)
|
||||
{
|
||||
Preconditions.checkArgument( string != null, "string cannot be null" );
|
||||
if ( string.startsWith( "#" ) && string.length() == 7 )
|
||||
{
|
||||
try
|
||||
{
|
||||
Integer.parseInt( string.substring( 1 ), 16 );
|
||||
} catch ( NumberFormatException ex )
|
||||
{
|
||||
throw new IllegalArgumentException( "Illegal hex string " + string );
|
||||
}
|
||||
|
||||
StringBuilder magic = new StringBuilder( COLOR_CHAR + "x" );
|
||||
for ( char c : string.substring( 1 ).toCharArray() )
|
||||
{
|
||||
magic.append( COLOR_CHAR ).append( c );
|
||||
}
|
||||
|
||||
return new ChatColor( string, magic.toString() );
|
||||
}
|
||||
|
||||
ChatColor defined = BY_NAME.get( string.toUpperCase( Locale.ROOT ) );
|
||||
if ( defined != null )
|
||||
{
|
||||
return defined;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException( "Could not parse ChatColor " + string );
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link Enum#valueOf(java.lang.Class, java.lang.String)}.
|
||||
*
|
||||
* @param name color name
|
||||
* @return ChatColor
|
||||
* @deprecated holdover from when this class was an enum
|
||||
*/
|
||||
@Deprecated
|
||||
public static ChatColor valueOf(String name)
|
||||
{
|
||||
Preconditions.checkNotNull( name, "Name is null" );
|
||||
|
||||
ChatColor defined = BY_NAME.get( name );
|
||||
Preconditions.checkArgument( defined != null, "No enum constant " + ChatColor.class.getName() + "." + name );
|
||||
|
||||
return defined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of all defined colors and formats.
|
||||
*
|
||||
* @return copied array of all colors and formats
|
||||
* @deprecated holdover from when this class was an enum
|
||||
*/
|
||||
@Deprecated
|
||||
public static ChatColor[] values()
|
||||
{
|
||||
return BY_CHAR.values().toArray( new ChatColor[ BY_CHAR.values().size() ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link Enum#name()}.
|
||||
*
|
||||
* @return constant name
|
||||
* @deprecated holdover from when this class was an enum
|
||||
*/
|
||||
@Deprecated
|
||||
public String name()
|
||||
{
|
||||
return getName().toUpperCase( Locale.ROOT );
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link Enum#ordinal()}.
|
||||
*
|
||||
* @return ordinal
|
||||
* @deprecated holdover from when this class was an enum
|
||||
*/
|
||||
@Deprecated
|
||||
public int ordinal()
|
||||
{
|
||||
Preconditions.checkArgument( ordinal >= 0, "Cannot get ordinal of hex color" );
|
||||
return ordinal;
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import java.util.List;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
@ -13,8 +12,7 @@ import net.md_5.bungee.api.chat.ComponentBuilder.FormatRetention;
|
||||
|
||||
@Setter
|
||||
@ToString(exclude = "parent")
|
||||
@EqualsAndHashCode
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(exclude = "parent")
|
||||
public abstract class BaseComponent
|
||||
{
|
||||
|
||||
@ -25,6 +23,10 @@ public abstract class BaseComponent
|
||||
* The color of this component and any child components (unless overridden)
|
||||
*/
|
||||
private ChatColor color;
|
||||
/**
|
||||
* The font of this component and any child components (unless overridden)
|
||||
*/
|
||||
private String font;
|
||||
/**
|
||||
* Whether this component and any child components (unless overridden) is
|
||||
* bold
|
||||
@ -76,6 +78,16 @@ public abstract class BaseComponent
|
||||
@Getter
|
||||
private HoverEvent hoverEvent;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*
|
||||
* @deprecated for use by internal classes only, will be removed.
|
||||
*/
|
||||
@Deprecated
|
||||
public BaseComponent()
|
||||
{
|
||||
}
|
||||
|
||||
BaseComponent(BaseComponent old)
|
||||
{
|
||||
copyFormatting( old, FormatRetention.ALL, true );
|
||||
@ -139,6 +151,10 @@ public abstract class BaseComponent
|
||||
{
|
||||
setColor( component.getColorRaw() );
|
||||
}
|
||||
if ( replace || font == null )
|
||||
{
|
||||
setFont( component.getFontRaw() );
|
||||
}
|
||||
if ( replace || bold == null )
|
||||
{
|
||||
setBold( component.isBoldRaw() );
|
||||
@ -275,6 +291,36 @@ public abstract class BaseComponent
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the font of this component. This uses the parent's font if this
|
||||
* component doesn't have one.
|
||||
*
|
||||
* @return the font of this component, or null if default font
|
||||
*/
|
||||
public String getFont()
|
||||
{
|
||||
if ( color == null )
|
||||
{
|
||||
if ( parent == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return parent.getFont();
|
||||
}
|
||||
return font;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the font of this component without checking the parents font. May
|
||||
* return null
|
||||
*
|
||||
* @return the font of this component
|
||||
*/
|
||||
public String getFontRaw()
|
||||
{
|
||||
return font;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this component is bold. This uses the parent's setting if
|
||||
* this component hasn't been set. false is returned if none of the parent
|
||||
@ -453,7 +499,7 @@ public abstract class BaseComponent
|
||||
*/
|
||||
public boolean hasFormatting()
|
||||
{
|
||||
return color != null || bold != null
|
||||
return color != null || font != null || bold != null
|
||||
|| italic != null || underlined != null
|
||||
|| strikethrough != null || obfuscated != null
|
||||
|| insertion != null || hoverEvent != null || clickEvent != null;
|
||||
@ -505,4 +551,29 @@ public abstract class BaseComponent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addFormat(StringBuilder builder)
|
||||
{
|
||||
builder.append( getColor() );
|
||||
if ( isBold() )
|
||||
{
|
||||
builder.append( ChatColor.BOLD );
|
||||
}
|
||||
if ( isItalic() )
|
||||
{
|
||||
builder.append( ChatColor.ITALIC );
|
||||
}
|
||||
if ( isUnderlined() )
|
||||
{
|
||||
builder.append( ChatColor.UNDERLINE );
|
||||
}
|
||||
if ( isStrikethrough() )
|
||||
{
|
||||
builder.append( ChatColor.STRIKETHROUGH );
|
||||
}
|
||||
if ( isObfuscated() )
|
||||
{
|
||||
builder.append( ChatColor.MAGIC );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,11 +13,11 @@ public final class ClickEvent
|
||||
{
|
||||
|
||||
/**
|
||||
* The type of action to perform on click
|
||||
* The type of action to perform on click.
|
||||
*/
|
||||
private final Action action;
|
||||
/**
|
||||
* Depends on action
|
||||
* Depends on the action.
|
||||
*
|
||||
* @see Action
|
||||
*/
|
||||
@ -28,29 +28,35 @@ public final class ClickEvent
|
||||
|
||||
/**
|
||||
* Open a url at the path given by
|
||||
* {@link net.md_5.bungee.api.chat.ClickEvent#value}
|
||||
* {@link net.md_5.bungee.api.chat.ClickEvent#value}.
|
||||
*/
|
||||
OPEN_URL,
|
||||
/**
|
||||
* Open a file at the path given by
|
||||
* {@link net.md_5.bungee.api.chat.ClickEvent#value}
|
||||
* {@link net.md_5.bungee.api.chat.ClickEvent#value}.
|
||||
*/
|
||||
OPEN_FILE,
|
||||
/**
|
||||
* Run the command given by
|
||||
* {@link net.md_5.bungee.api.chat.ClickEvent#value}
|
||||
* {@link net.md_5.bungee.api.chat.ClickEvent#value}.
|
||||
*/
|
||||
RUN_COMMAND,
|
||||
/**
|
||||
* Inserts the string given by
|
||||
* {@link net.md_5.bungee.api.chat.ClickEvent#value} into the players
|
||||
* text box
|
||||
* {@link net.md_5.bungee.api.chat.ClickEvent#value} into the player's
|
||||
* text box.
|
||||
*/
|
||||
SUGGEST_COMMAND,
|
||||
/**
|
||||
* Change to the page number given by
|
||||
* {@link net.md_5.bungee.api.chat.ClickEvent#value} in a book
|
||||
* {@link net.md_5.bungee.api.chat.ClickEvent#value} in a book.
|
||||
*/
|
||||
CHANGE_PAGE
|
||||
CHANGE_PAGE,
|
||||
/**
|
||||
* Copy the string given by
|
||||
* {@link net.md_5.bungee.api.chat.ClickEvent#value} into the player's
|
||||
* clipboard.
|
||||
*/
|
||||
COPY_TO_CLIPBOARD
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package net.md_5.bungee.api.chat;
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
|
||||
/**
|
||||
@ -23,11 +25,29 @@ import net.md_5.bungee.api.ChatColor;
|
||||
* part's formatting
|
||||
* </p>
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
public final class ComponentBuilder
|
||||
{
|
||||
|
||||
private BaseComponent current;
|
||||
/**
|
||||
* The position for the current part to modify. Modified cursors will
|
||||
* automatically reset to the last part after appending new components.
|
||||
* Default value at -1 to assert that the builder has no parts.
|
||||
*/
|
||||
@Getter
|
||||
private int cursor = -1;
|
||||
@Getter
|
||||
private final List<BaseComponent> parts = new ArrayList<BaseComponent>();
|
||||
private BaseComponent dummy;
|
||||
|
||||
private ComponentBuilder(BaseComponent[] parts)
|
||||
{
|
||||
for ( BaseComponent baseComponent : parts )
|
||||
{
|
||||
this.parts.add( baseComponent.duplicate() );
|
||||
}
|
||||
resetCursor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ComponentBuilder from the other given ComponentBuilder to clone
|
||||
@ -37,11 +57,7 @@ public final class ComponentBuilder
|
||||
*/
|
||||
public ComponentBuilder(ComponentBuilder original)
|
||||
{
|
||||
current = original.current.duplicate();
|
||||
for ( BaseComponent baseComponent : original.parts )
|
||||
{
|
||||
parts.add( baseComponent.duplicate() );
|
||||
}
|
||||
this( original.parts.toArray( new BaseComponent[ original.parts.size() ] ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -51,7 +67,7 @@ public final class ComponentBuilder
|
||||
*/
|
||||
public ComponentBuilder(String text)
|
||||
{
|
||||
current = new TextComponent( text );
|
||||
this( new TextComponent( text ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -61,7 +77,58 @@ public final class ComponentBuilder
|
||||
*/
|
||||
public ComponentBuilder(BaseComponent component)
|
||||
{
|
||||
current = component.duplicate();
|
||||
|
||||
this( new BaseComponent[]
|
||||
{
|
||||
component
|
||||
} );
|
||||
}
|
||||
|
||||
private BaseComponent getDummy()
|
||||
{
|
||||
if ( dummy == null )
|
||||
{
|
||||
dummy = new BaseComponent()
|
||||
{
|
||||
@Override
|
||||
public BaseComponent duplicate()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
};
|
||||
}
|
||||
return dummy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the cursor to index of the last element.
|
||||
*
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder resetCursor()
|
||||
{
|
||||
cursor = parts.size() - 1;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position of the current component to be modified
|
||||
*
|
||||
* @param pos the cursor position synonymous to an element position for a
|
||||
* list
|
||||
* @return this ComponentBuilder for chaining
|
||||
* @throws IndexOutOfBoundsException if the index is out of range
|
||||
* ({@code index < 0 || index >= size()})
|
||||
*/
|
||||
public ComponentBuilder setCursor(int pos) throws IndexOutOfBoundsException
|
||||
{
|
||||
if ( ( this.cursor != pos ) && ( pos < 0 || pos >= parts.size() ) )
|
||||
{
|
||||
throw new IndexOutOfBoundsException( "Cursor out of bounds (expected between 0 + " + ( parts.size() - 1 ) + ")" );
|
||||
}
|
||||
|
||||
this.cursor = pos;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,11 +155,18 @@ public final class ComponentBuilder
|
||||
*/
|
||||
public ComponentBuilder append(BaseComponent component, FormatRetention retention)
|
||||
{
|
||||
parts.add( current );
|
||||
|
||||
BaseComponent previous = current;
|
||||
current = component.duplicate();
|
||||
current.copyFormatting( previous, retention, false );
|
||||
BaseComponent previous = ( parts.isEmpty() ) ? null : parts.get( parts.size() - 1 );
|
||||
if ( previous == null )
|
||||
{
|
||||
previous = dummy;
|
||||
dummy = null;
|
||||
}
|
||||
if ( previous != null )
|
||||
{
|
||||
component.copyFormatting( previous, retention, false );
|
||||
}
|
||||
parts.add( component );
|
||||
resetCursor();
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -122,13 +196,9 @@ public final class ComponentBuilder
|
||||
{
|
||||
Preconditions.checkArgument( components.length != 0, "No components to append" );
|
||||
|
||||
BaseComponent previous = current;
|
||||
for ( BaseComponent component : components )
|
||||
{
|
||||
parts.add( current );
|
||||
|
||||
current = component.duplicate();
|
||||
current.copyFormatting( previous, retention, false );
|
||||
append( component, retention );
|
||||
}
|
||||
|
||||
return this;
|
||||
@ -170,13 +240,7 @@ public final class ComponentBuilder
|
||||
*/
|
||||
public ComponentBuilder append(String text, FormatRetention retention)
|
||||
{
|
||||
parts.add( current );
|
||||
|
||||
BaseComponent old = current;
|
||||
current = new TextComponent( text );
|
||||
current.copyFormatting( old, retention, false );
|
||||
|
||||
return this;
|
||||
return append( new TextComponent( text ), retention );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -210,6 +274,44 @@ public final class ComponentBuilder
|
||||
return joiner.join( this, retention );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the component part at the position of given index.
|
||||
*
|
||||
* @param pos the index to remove at
|
||||
* @throws IndexOutOfBoundsException if the index is out of range
|
||||
* ({@code index < 0 || index >= size()})
|
||||
*/
|
||||
public void removeComponent(int pos) throws IndexOutOfBoundsException
|
||||
{
|
||||
if ( parts.remove( pos ) != null )
|
||||
{
|
||||
resetCursor();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the component part at the position of given index.
|
||||
*
|
||||
* @param pos the index to find
|
||||
* @return the component
|
||||
* @throws IndexOutOfBoundsException if the index is out of range
|
||||
* ({@code index < 0 || index >= size()})
|
||||
*/
|
||||
public BaseComponent getComponent(int pos) throws IndexOutOfBoundsException
|
||||
{
|
||||
return parts.get( pos );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the component at the position of the cursor.
|
||||
*
|
||||
* @return the active component or null if builder is empty
|
||||
*/
|
||||
public BaseComponent getCurrentComponent()
|
||||
{
|
||||
return ( cursor == -1 ) ? getDummy() : parts.get( cursor );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color of the current part.
|
||||
*
|
||||
@ -218,7 +320,7 @@ public final class ComponentBuilder
|
||||
*/
|
||||
public ComponentBuilder color(ChatColor color)
|
||||
{
|
||||
current.setColor( color );
|
||||
getCurrentComponent().setColor( color );
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -230,7 +332,7 @@ public final class ComponentBuilder
|
||||
*/
|
||||
public ComponentBuilder bold(boolean bold)
|
||||
{
|
||||
current.setBold( bold );
|
||||
getCurrentComponent().setBold( bold );
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -242,7 +344,7 @@ public final class ComponentBuilder
|
||||
*/
|
||||
public ComponentBuilder italic(boolean italic)
|
||||
{
|
||||
current.setItalic( italic );
|
||||
getCurrentComponent().setItalic( italic );
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -254,7 +356,7 @@ public final class ComponentBuilder
|
||||
*/
|
||||
public ComponentBuilder underlined(boolean underlined)
|
||||
{
|
||||
current.setUnderlined( underlined );
|
||||
getCurrentComponent().setUnderlined( underlined );
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -266,7 +368,7 @@ public final class ComponentBuilder
|
||||
*/
|
||||
public ComponentBuilder strikethrough(boolean strikethrough)
|
||||
{
|
||||
current.setStrikethrough( strikethrough );
|
||||
getCurrentComponent().setStrikethrough( strikethrough );
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -278,7 +380,7 @@ public final class ComponentBuilder
|
||||
*/
|
||||
public ComponentBuilder obfuscated(boolean obfuscated)
|
||||
{
|
||||
current.setObfuscated( obfuscated );
|
||||
getCurrentComponent().setObfuscated( obfuscated );
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -290,7 +392,7 @@ public final class ComponentBuilder
|
||||
*/
|
||||
public ComponentBuilder insertion(String insertion)
|
||||
{
|
||||
current.setInsertion( insertion );
|
||||
getCurrentComponent().setInsertion( insertion );
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -302,7 +404,7 @@ public final class ComponentBuilder
|
||||
*/
|
||||
public ComponentBuilder event(ClickEvent clickEvent)
|
||||
{
|
||||
current.setClickEvent( clickEvent );
|
||||
getCurrentComponent().setClickEvent( clickEvent );
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -314,7 +416,7 @@ public final class ComponentBuilder
|
||||
*/
|
||||
public ComponentBuilder event(HoverEvent hoverEvent)
|
||||
{
|
||||
current.setHoverEvent( hoverEvent );
|
||||
getCurrentComponent().setHoverEvent( hoverEvent );
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -336,24 +438,28 @@ public final class ComponentBuilder
|
||||
*/
|
||||
public ComponentBuilder retain(FormatRetention retention)
|
||||
{
|
||||
current.retain( retention );
|
||||
getCurrentComponent().retain( retention );
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the components needed to display the message created by this
|
||||
* builder.
|
||||
* builder.git
|
||||
*
|
||||
* @return the created components
|
||||
*/
|
||||
public BaseComponent[] create()
|
||||
{
|
||||
BaseComponent[] result = parts.toArray( new BaseComponent[ parts.size() + 1 ] );
|
||||
result[parts.size()] = current;
|
||||
return result;
|
||||
BaseComponent[] cloned = new BaseComponent[ parts.size() ];
|
||||
int i = 0;
|
||||
for ( BaseComponent part : parts )
|
||||
{
|
||||
cloned[i++] = part.duplicate();
|
||||
}
|
||||
return cloned;
|
||||
}
|
||||
|
||||
public static enum FormatRetention
|
||||
public enum FormatRetention
|
||||
{
|
||||
|
||||
/**
|
||||
|
@ -5,7 +5,6 @@ import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ -45,7 +44,7 @@ public final class KeybindComponent extends BaseComponent
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseComponent duplicate()
|
||||
public KeybindComponent duplicate()
|
||||
{
|
||||
return new KeybindComponent( this );
|
||||
}
|
||||
@ -60,29 +59,8 @@ public final class KeybindComponent extends BaseComponent
|
||||
@Override
|
||||
protected void toLegacyText(StringBuilder builder)
|
||||
{
|
||||
builder.append( getColor() );
|
||||
if ( isBold() )
|
||||
{
|
||||
builder.append( ChatColor.BOLD );
|
||||
}
|
||||
if ( isItalic() )
|
||||
{
|
||||
builder.append( ChatColor.ITALIC );
|
||||
}
|
||||
if ( isUnderlined() )
|
||||
{
|
||||
builder.append( ChatColor.UNDERLINE );
|
||||
}
|
||||
if ( isStrikethrough() )
|
||||
{
|
||||
builder.append( ChatColor.STRIKETHROUGH );
|
||||
}
|
||||
if ( isObfuscated() )
|
||||
{
|
||||
builder.append( ChatColor.MAGIC );
|
||||
}
|
||||
addFormat( builder );
|
||||
builder.append( getKeybind() );
|
||||
|
||||
super.toLegacyText( builder );
|
||||
}
|
||||
}
|
||||
|
@ -84,9 +84,17 @@ public final class ScoreComponent extends BaseComponent
|
||||
return new ScoreComponent( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toPlainText(StringBuilder builder)
|
||||
{
|
||||
builder.append( this.value );
|
||||
super.toPlainText( builder );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toLegacyText(StringBuilder builder)
|
||||
{
|
||||
addFormat( builder );
|
||||
builder.append( this.value );
|
||||
super.toLegacyText( builder );
|
||||
}
|
||||
|
@ -50,9 +50,17 @@ public final class SelectorComponent extends BaseComponent
|
||||
return new SelectorComponent( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toPlainText(StringBuilder builder)
|
||||
{
|
||||
builder.append( this.selector );
|
||||
super.toPlainText( builder );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toLegacyText(StringBuilder builder)
|
||||
{
|
||||
addFormat( builder );
|
||||
builder.append( this.selector );
|
||||
super.toLegacyText( builder );
|
||||
}
|
||||
|
@ -63,7 +63,27 @@ public final class TextComponent extends BaseComponent
|
||||
{
|
||||
c += 32;
|
||||
}
|
||||
ChatColor format = ChatColor.getByChar( c );
|
||||
ChatColor format;
|
||||
if ( c == 'x' && i + 12 < message.length() )
|
||||
{
|
||||
StringBuilder hex = new StringBuilder( "#" );
|
||||
for ( int j = 0; j < 6; j++ )
|
||||
{
|
||||
hex.append( message.charAt( i + 2 + ( j * 2 ) ) );
|
||||
}
|
||||
try
|
||||
{
|
||||
format = ChatColor.of( hex.toString() );
|
||||
} catch ( IllegalArgumentException ex )
|
||||
{
|
||||
format = null;
|
||||
}
|
||||
|
||||
i += 12;
|
||||
} else
|
||||
{
|
||||
format = ChatColor.getByChar( c );
|
||||
}
|
||||
if ( format == null )
|
||||
{
|
||||
continue;
|
||||
@ -76,29 +96,30 @@ public final class TextComponent extends BaseComponent
|
||||
builder = new StringBuilder();
|
||||
components.add( old );
|
||||
}
|
||||
switch ( format )
|
||||
if ( format == ChatColor.BOLD )
|
||||
{
|
||||
case BOLD:
|
||||
component.setBold( true );
|
||||
break;
|
||||
case ITALIC:
|
||||
component.setItalic( true );
|
||||
break;
|
||||
case UNDERLINE:
|
||||
component.setUnderlined( true );
|
||||
break;
|
||||
case STRIKETHROUGH:
|
||||
component.setStrikethrough( true );
|
||||
break;
|
||||
case MAGIC:
|
||||
component.setObfuscated( true );
|
||||
break;
|
||||
case RESET:
|
||||
format = defaultColor;
|
||||
default:
|
||||
component = new TextComponent();
|
||||
component.setColor( format );
|
||||
break;
|
||||
component.setBold( true );
|
||||
} else if ( format == ChatColor.ITALIC )
|
||||
{
|
||||
component.setItalic( true );
|
||||
} else if ( format == ChatColor.UNDERLINE )
|
||||
{
|
||||
component.setUnderlined( true );
|
||||
} else if ( format == ChatColor.STRIKETHROUGH )
|
||||
{
|
||||
component.setStrikethrough( true );
|
||||
} else if ( format == ChatColor.MAGIC )
|
||||
{
|
||||
component.setObfuscated( true );
|
||||
} else if ( format == ChatColor.RESET )
|
||||
{
|
||||
format = defaultColor;
|
||||
component = new TextComponent();
|
||||
component.setColor( format );
|
||||
} else
|
||||
{
|
||||
component = new TextComponent();
|
||||
component.setColor( format );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@ -172,7 +193,11 @@ public final class TextComponent extends BaseComponent
|
||||
*/
|
||||
public TextComponent(BaseComponent... extras)
|
||||
{
|
||||
setText( "" );
|
||||
this();
|
||||
if ( extras.length == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
setExtra( new ArrayList<BaseComponent>( Arrays.asList( extras ) ) );
|
||||
}
|
||||
|
||||
@ -182,7 +207,7 @@ public final class TextComponent extends BaseComponent
|
||||
* @return the duplicate of this TextComponent.
|
||||
*/
|
||||
@Override
|
||||
public BaseComponent duplicate()
|
||||
public TextComponent duplicate()
|
||||
{
|
||||
return new TextComponent( this );
|
||||
}
|
||||
@ -197,27 +222,7 @@ public final class TextComponent extends BaseComponent
|
||||
@Override
|
||||
protected void toLegacyText(StringBuilder builder)
|
||||
{
|
||||
builder.append( getColor() );
|
||||
if ( isBold() )
|
||||
{
|
||||
builder.append( ChatColor.BOLD );
|
||||
}
|
||||
if ( isItalic() )
|
||||
{
|
||||
builder.append( ChatColor.ITALIC );
|
||||
}
|
||||
if ( isUnderlined() )
|
||||
{
|
||||
builder.append( ChatColor.UNDERLINE );
|
||||
}
|
||||
if ( isStrikethrough() )
|
||||
{
|
||||
builder.append( ChatColor.STRIKETHROUGH );
|
||||
}
|
||||
if ( isObfuscated() )
|
||||
{
|
||||
builder.append( ChatColor.MAGIC );
|
||||
}
|
||||
addFormat( builder );
|
||||
builder.append( text );
|
||||
super.toLegacyText( builder );
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.chat.TranslationRegistry;
|
||||
|
||||
@Getter
|
||||
@ -56,12 +55,12 @@ public final class TranslatableComponent extends BaseComponent
|
||||
/**
|
||||
* Creates a translatable component with the passed substitutions
|
||||
*
|
||||
* @see #translate
|
||||
* @see #setWith(java.util.List)
|
||||
* @param translate the translation key
|
||||
* @param with the {@link java.lang.String}s and
|
||||
* {@link net.md_5.bungee.api.chat.BaseComponent}s to use into the
|
||||
* translation
|
||||
* @see #translate
|
||||
* @see #setWith(java.util.List)
|
||||
*/
|
||||
public TranslatableComponent(String translate, Object... with)
|
||||
{
|
||||
@ -89,7 +88,7 @@ public final class TranslatableComponent extends BaseComponent
|
||||
* @return the duplicate of this TranslatableComponent.
|
||||
*/
|
||||
@Override
|
||||
public BaseComponent duplicate()
|
||||
public TranslatableComponent duplicate()
|
||||
{
|
||||
return new TranslatableComponent( this );
|
||||
}
|
||||
@ -139,43 +138,18 @@ public final class TranslatableComponent extends BaseComponent
|
||||
@Override
|
||||
protected void toPlainText(StringBuilder builder)
|
||||
{
|
||||
String trans = TranslationRegistry.INSTANCE.translate( translate );
|
||||
|
||||
Matcher matcher = format.matcher( trans );
|
||||
int position = 0;
|
||||
int i = 0;
|
||||
while ( matcher.find( position ) )
|
||||
{
|
||||
int pos = matcher.start();
|
||||
if ( pos != position )
|
||||
{
|
||||
builder.append( trans.substring( position, pos ) );
|
||||
}
|
||||
position = matcher.end();
|
||||
|
||||
String formatCode = matcher.group( 2 );
|
||||
switch ( formatCode.charAt( 0 ) )
|
||||
{
|
||||
case 's':
|
||||
case 'd':
|
||||
String withIndex = matcher.group( 1 );
|
||||
with.get( withIndex != null ? Integer.parseInt( withIndex ) - 1 : i++ ).toPlainText( builder );
|
||||
break;
|
||||
case '%':
|
||||
builder.append( '%' );
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( trans.length() != position )
|
||||
{
|
||||
builder.append( trans.substring( position, trans.length() ) );
|
||||
}
|
||||
|
||||
convert( builder, false );
|
||||
super.toPlainText( builder );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toLegacyText(StringBuilder builder)
|
||||
{
|
||||
convert( builder, true );
|
||||
super.toLegacyText( builder );
|
||||
}
|
||||
|
||||
private void convert(StringBuilder builder, boolean applyFormat)
|
||||
{
|
||||
String trans = TranslationRegistry.INSTANCE.translate( translate );
|
||||
|
||||
@ -187,7 +161,10 @@ public final class TranslatableComponent extends BaseComponent
|
||||
int pos = matcher.start();
|
||||
if ( pos != position )
|
||||
{
|
||||
addFormat( builder );
|
||||
if ( applyFormat )
|
||||
{
|
||||
addFormat( builder );
|
||||
}
|
||||
builder.append( trans.substring( position, pos ) );
|
||||
}
|
||||
position = matcher.end();
|
||||
@ -198,44 +175,32 @@ public final class TranslatableComponent extends BaseComponent
|
||||
case 's':
|
||||
case 'd':
|
||||
String withIndex = matcher.group( 1 );
|
||||
with.get( withIndex != null ? Integer.parseInt( withIndex ) - 1 : i++ ).toLegacyText( builder );
|
||||
|
||||
BaseComponent withComponent = with.get( withIndex != null ? Integer.parseInt( withIndex ) - 1 : i++ );
|
||||
if ( applyFormat )
|
||||
{
|
||||
withComponent.toLegacyText( builder );
|
||||
} else
|
||||
{
|
||||
withComponent.toPlainText( builder );
|
||||
}
|
||||
break;
|
||||
case '%':
|
||||
addFormat( builder );
|
||||
if ( applyFormat )
|
||||
{
|
||||
addFormat( builder );
|
||||
}
|
||||
builder.append( '%' );
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( trans.length() != position )
|
||||
{
|
||||
addFormat( builder );
|
||||
if ( applyFormat )
|
||||
{
|
||||
addFormat( builder );
|
||||
}
|
||||
builder.append( trans.substring( position, trans.length() ) );
|
||||
}
|
||||
super.toLegacyText( builder );
|
||||
}
|
||||
|
||||
private void addFormat(StringBuilder builder)
|
||||
{
|
||||
builder.append( getColor() );
|
||||
if ( isBold() )
|
||||
{
|
||||
builder.append( ChatColor.BOLD );
|
||||
}
|
||||
if ( isItalic() )
|
||||
{
|
||||
builder.append( ChatColor.ITALIC );
|
||||
}
|
||||
if ( isUnderlined() )
|
||||
{
|
||||
builder.append( ChatColor.UNDERLINE );
|
||||
}
|
||||
if ( isStrikethrough() )
|
||||
{
|
||||
builder.append( ChatColor.STRIKETHROUGH );
|
||||
}
|
||||
if ( isObfuscated() )
|
||||
{
|
||||
builder.append( ChatColor.MAGIC );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,11 @@ public class BaseComponentSerializer
|
||||
{
|
||||
if ( object.has( "color" ) )
|
||||
{
|
||||
component.setColor( ChatColor.valueOf( object.get( "color" ).getAsString().toUpperCase( Locale.ROOT ) ) );
|
||||
component.setColor( ChatColor.of( object.get( "color" ).getAsString() ) );
|
||||
}
|
||||
if ( object.has( "font" ) )
|
||||
{
|
||||
component.setFont( object.get( "font" ).getAsString() );
|
||||
}
|
||||
if ( object.has( "bold" ) )
|
||||
{
|
||||
@ -93,6 +97,10 @@ public class BaseComponentSerializer
|
||||
{
|
||||
object.addProperty( "color", component.getColorRaw().getName() );
|
||||
}
|
||||
if ( component.getFontRaw() != null )
|
||||
{
|
||||
object.addProperty( "font", component.getFontRaw() );
|
||||
}
|
||||
if ( component.isBoldRaw() != null )
|
||||
{
|
||||
object.addProperty( "bold", component.isBoldRaw() );
|
||||
|
@ -24,7 +24,7 @@ public class TranslatableComponentSerializer extends BaseComponentSerializer imp
|
||||
component.setTranslate( object.get( "translate" ).getAsString() );
|
||||
if ( object.has( "with" ) )
|
||||
{
|
||||
component.setWith( Arrays.asList( (BaseComponent[]) context.deserialize( object.get( "with" ), BaseComponent[].class ) ) );
|
||||
component.setWith( Arrays.asList( context.<BaseComponent[]>deserialize( object.get( "with" ), BaseComponent[].class ) ) );
|
||||
}
|
||||
return component;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.md_5.bungee.api.chat;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@ -11,16 +12,112 @@ import org.junit.Test;
|
||||
public class ComponentsTest
|
||||
{
|
||||
|
||||
@Test
|
||||
public void testEmptyComponentBuilder()
|
||||
{
|
||||
ComponentBuilder builder = new ComponentBuilder();
|
||||
|
||||
BaseComponent[] parts = builder.create();
|
||||
Assert.assertEquals( parts.length, 0 );
|
||||
|
||||
for ( int i = 0; i < 3; i++ )
|
||||
{
|
||||
builder.append( "part:" + i );
|
||||
parts = builder.create();
|
||||
Assert.assertEquals( parts.length, i + 1 );
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDummyRetaining()
|
||||
{
|
||||
ComponentBuilder builder = new ComponentBuilder();
|
||||
Assert.assertNotNull( builder.getCurrentComponent() );
|
||||
builder.color( ChatColor.GREEN );
|
||||
builder.append( "test ", ComponentBuilder.FormatRetention.ALL );
|
||||
Assert.assertEquals( builder.getCurrentComponent().getColor(), ChatColor.GREEN );
|
||||
}
|
||||
|
||||
@Test(expected = IndexOutOfBoundsException.class)
|
||||
public void testComponentGettingExceptions()
|
||||
{
|
||||
ComponentBuilder builder = new ComponentBuilder();
|
||||
builder.getComponent( -1 );
|
||||
builder.getComponent( 0 );
|
||||
builder.getComponent( 1 );
|
||||
BaseComponent component = new TextComponent( "Hello" );
|
||||
builder.append( component );
|
||||
Assert.assertEquals( builder.getComponent( 0 ), component );
|
||||
builder.getComponent( 1 );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComponentParting()
|
||||
{
|
||||
ComponentBuilder builder = new ComponentBuilder();
|
||||
TextComponent apple = new TextComponent( "apple" );
|
||||
builder.append( apple );
|
||||
Assert.assertEquals( builder.getCurrentComponent(), apple );
|
||||
Assert.assertEquals( builder.getComponent( 0 ), apple );
|
||||
|
||||
TextComponent mango = new TextComponent( "mango" );
|
||||
TextComponent orange = new TextComponent( "orange" );
|
||||
builder.append( mango );
|
||||
builder.append( orange );
|
||||
builder.removeComponent( 1 ); // Removing mango
|
||||
Assert.assertEquals( builder.getComponent( 0 ), apple );
|
||||
Assert.assertEquals( builder.getComponent( 1 ), orange );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToLegacyFromLegacy()
|
||||
{
|
||||
String text = "§a§lHello §f§kworld§7!";
|
||||
Assert.assertEquals( text, TextComponent.toLegacyText( TextComponent.fromLegacyText( text ) ) );
|
||||
}
|
||||
|
||||
@Test(expected = IndexOutOfBoundsException.class)
|
||||
public void testComponentBuilderCursorInvalidPos()
|
||||
{
|
||||
ComponentBuilder builder = new ComponentBuilder();
|
||||
builder.append( new TextComponent( "Apple, " ) );
|
||||
builder.append( new TextComponent( "Orange, " ) );
|
||||
builder.setCursor( -1 );
|
||||
builder.setCursor( 2 );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComponentBuilderCursor()
|
||||
{
|
||||
TextComponent t1, t2, t3;
|
||||
ComponentBuilder builder = new ComponentBuilder();
|
||||
Assert.assertEquals( builder.getCursor(), -1 );
|
||||
builder.append( t1 = new TextComponent( "Apple, " ) );
|
||||
Assert.assertEquals( builder.getCursor(), 0 );
|
||||
builder.append( t2 = new TextComponent( "Orange, " ) );
|
||||
builder.append( t3 = new TextComponent( "Mango, " ) );
|
||||
Assert.assertEquals( builder.getCursor(), 2 );
|
||||
|
||||
builder.setCursor( 0 );
|
||||
Assert.assertEquals( builder.getCurrentComponent(), t1 );
|
||||
|
||||
// Test that appending new components updates the position to the new list size
|
||||
// after having previously set it to 0 (first component)
|
||||
builder.append( new TextComponent( "and Grapefruit" ) );
|
||||
Assert.assertEquals( builder.getCursor(), 3 );
|
||||
|
||||
builder.setCursor( 0 );
|
||||
builder.resetCursor();
|
||||
Assert.assertEquals( builder.getCursor(), 3 );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLegacyComponentBuilderAppend()
|
||||
{
|
||||
String text = "§a§lHello §r§kworld§7!";
|
||||
BaseComponent[] components = TextComponent.fromLegacyText( text );
|
||||
BaseComponent[] builderComponents = new ComponentBuilder( "" ).append( components ).create();
|
||||
BaseComponent[] builderComponents = new ComponentBuilder().append( components ).create();
|
||||
List<BaseComponent> list = new ArrayList<BaseComponent>( Arrays.asList( builderComponents ) );
|
||||
// Remove the first element (empty text component). This needs to be done because toLegacyText always
|
||||
// appends &f regardless if the color is non null or not and would otherwise mess with our unit test.
|
||||
list.remove( 0 );
|
||||
Assert.assertEquals(
|
||||
TextComponent.toLegacyText( components ),
|
||||
TextComponent.toLegacyText( list.toArray( new BaseComponent[ list.size() ] ) )
|
||||
@ -28,7 +125,7 @@ public class ComponentsTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComponentFormatRetention()
|
||||
public void testFormatRetentionCopyFormatting()
|
||||
{
|
||||
TextComponent first = new TextComponent( "Hello" );
|
||||
first.setBold( true );
|
||||
@ -47,7 +144,7 @@ public class ComponentsTest
|
||||
@Test
|
||||
public void testBuilderClone()
|
||||
{
|
||||
ComponentBuilder builder = new ComponentBuilder( "Hel" ).color( ChatColor.RED ).append( "lo" ).color( ChatColor.DARK_RED );
|
||||
ComponentBuilder builder = new ComponentBuilder( "Hello " ).color( ChatColor.RED ).append( "world" ).color( ChatColor.DARK_RED );
|
||||
ComponentBuilder cloned = new ComponentBuilder( builder );
|
||||
|
||||
Assert.assertEquals( TextComponent.toLegacyText( builder.create() ), TextComponent.toLegacyText( cloned.create() ) );
|
||||
@ -313,6 +410,41 @@ public class ComponentsTest
|
||||
Assert.assertEquals( text, roundtripLegacyText );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals()
|
||||
{
|
||||
TextComponent first = new TextComponent( "Hello, " );
|
||||
first.addExtra( new TextComponent( "World!" ) );
|
||||
|
||||
TextComponent second = new TextComponent( "Hello, " );
|
||||
second.addExtra( new TextComponent( "World!" ) );
|
||||
|
||||
Assert.assertEquals( first, second );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotEquals()
|
||||
{
|
||||
TextComponent first = new TextComponent( "Hello, " );
|
||||
first.addExtra( new TextComponent( "World." ) );
|
||||
|
||||
TextComponent second = new TextComponent( "Hello, " );
|
||||
second.addExtra( new TextComponent( "World!" ) );
|
||||
|
||||
Assert.assertNotEquals( first, second );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLegacyHack()
|
||||
{
|
||||
BaseComponent[] hexColored = new ComponentBuilder().color( ChatColor.of( Color.GRAY ) ).append( "Test" ).create();
|
||||
String legacy = TextComponent.toLegacyText( hexColored );
|
||||
|
||||
BaseComponent[] reColored = TextComponent.fromLegacyText( legacy );
|
||||
|
||||
Assert.assertArrayEquals( hexColored, reColored );
|
||||
}
|
||||
|
||||
private String fromAndToLegacyText(String legacyText)
|
||||
{
|
||||
return BaseComponent.toLegacyText( TextComponent.fromLegacyText( legacyText ) );
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.md_5.bungee.api.chat;
|
||||
|
||||
import net.md_5.bungee.chat.ComponentSerializer;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
@ -13,4 +14,15 @@ public class TranslatableComponentTest
|
||||
Assert.assertEquals( "Test string with 2 placeholders: aoeu", testComponent.toPlainText() );
|
||||
Assert.assertEquals( "§fTest string with §f2§f placeholders: §faoeu", testComponent.toLegacyText() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJsonSerialisation()
|
||||
{
|
||||
TranslatableComponent testComponent = new TranslatableComponent( "Test string with %s placeholder", "a" );
|
||||
String jsonString = ComponentSerializer.toString( testComponent );
|
||||
BaseComponent[] baseComponents = ComponentSerializer.parse( jsonString );
|
||||
|
||||
Assert.assertEquals( "Test string with a placeholder", TextComponent.toPlainText( baseComponents ) );
|
||||
Assert.assertEquals( "§fTest string with §fa§f placeholder", TextComponent.toLegacyText( baseComponents ) );
|
||||
}
|
||||
}
|
||||
|
@ -14,13 +14,23 @@
|
||||
|
||||
<!-- See http://checkstyle.sourceforge.net/config_misc.html -->
|
||||
<module name="RegexpSingleline">
|
||||
<property name="format" value="\s+$"/>
|
||||
<property name="minimum" value="0"/>
|
||||
<property name="maximum" value="0"/>
|
||||
<property name="message" value="Line has trailing spaces."/>
|
||||
<property name="format" value="\s+$"/>
|
||||
<property name="minimum" value="0"/>
|
||||
<property name="maximum" value="0"/>
|
||||
<property name="message" value="Line has trailing spaces."/>
|
||||
</module>
|
||||
|
||||
<module name="TreeWalker">
|
||||
<!-- See https://checkstyle.org/config_javadoc.html -->
|
||||
<module name="AtclauseOrder"/>
|
||||
<module name="InvalidJavadocPosition"/>
|
||||
<module name="JavadocBlockTagLocation"/>
|
||||
<module name="JavadocContentLocationCheck"/>
|
||||
<module name="JavadocMethod"/>
|
||||
<module name="JavadocType"/>
|
||||
<module name="MissingJavadocPackage"/>
|
||||
<module name="NonEmptyAtclauseDescription"/>
|
||||
|
||||
<!-- See http://checkstyle.sourceforge.net/config_filters.html -->
|
||||
<module name="SuppressionCommentFilter"/>
|
||||
|
||||
@ -35,14 +45,43 @@
|
||||
<module name="RedundantImport"/>
|
||||
<module name="UnusedImports"/>
|
||||
|
||||
<!-- See https://checkstyle.org/config_whitespace.html -->
|
||||
<module name="GenericWhitespace"/>
|
||||
<module name="MethodParamPad"/>
|
||||
<module name="NoLineWrap"/>
|
||||
<module name="NoWhitespaceAfter"/>
|
||||
<module name="NoWhitespaceBefore"/>
|
||||
<module name="OperatorWrap"/>
|
||||
<module name="ParenPad">
|
||||
<property name="option" value="nospace"/>
|
||||
<property name="tokens" value="ANNOTATION, CTOR_DEF, METHOD_DEF"/>
|
||||
</module>
|
||||
<module name="ParenPad">
|
||||
<property name="option" value="space"/>
|
||||
<property name="tokens" value="ANNOTATION_FIELD_DEF, CTOR_CALL, DOT, ENUM_CONSTANT_DEF, EXPR, LITERAL_CATCH, LITERAL_DO, LITERAL_FOR, LITERAL_IF, LITERAL_NEW, LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_WHILE, METHOD_CALL, QUESTION, RESOURCE_SPECIFICATION, SUPER_CTOR_CALL, LAMBDA"/>
|
||||
</module>
|
||||
<module name="SingleSpaceSeparator"/>
|
||||
<module name="TypecastParenPad"/>
|
||||
<module name="WhitespaceAfter"/>
|
||||
<module name="WhitespaceAround"/>
|
||||
|
||||
<!-- See http://checkstyle.sourceforge.net/config_modifiers.html -->
|
||||
<module name="ModifierOrder"/>
|
||||
|
||||
<!-- See https://checkstyle.org/config_blocks.html -->
|
||||
<module name="AvoidNestedBlocks"/>
|
||||
<module name="LeftCurly">
|
||||
<property name="option" value="nl"/>
|
||||
</module>
|
||||
<module name="RightCurly"/>
|
||||
|
||||
<!-- See http://checkstyle.sourceforge.net/config_design.html -->
|
||||
<module name="FinalClass"/>
|
||||
|
||||
<!-- See http://checkstyle.sourceforge.net/config_misc.html -->
|
||||
<module name="ArrayTypeStyle"/>
|
||||
<module name="CommentsIndentation"/>
|
||||
<module name="Indentation"/>
|
||||
<module name="UpperEll"/>
|
||||
</module>
|
||||
</module>
|
||||
|
@ -6,24 +6,32 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-config</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-Config</name>
|
||||
<description>Generic java configuration API intended for use with BungeeCord</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.8.0</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>1.23</version>
|
||||
<version>1.25</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
@ -15,7 +15,21 @@ public abstract class ConfigurationProvider
|
||||
|
||||
static
|
||||
{
|
||||
providers.put( YamlConfiguration.class, new YamlConfiguration() );
|
||||
try
|
||||
{
|
||||
providers.put( YamlConfiguration.class, new YamlConfiguration() );
|
||||
} catch ( NoClassDefFoundError ex )
|
||||
{
|
||||
// Ignore, no SnakeYAML
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
providers.put( JsonConfiguration.class, new JsonConfiguration() );
|
||||
} catch ( NoClassDefFoundError ex )
|
||||
{
|
||||
// Ignore, no Gson
|
||||
}
|
||||
}
|
||||
|
||||
public static ConfigurationProvider getProvider(Class<? extends ConfigurationProvider> provider)
|
||||
|
@ -0,0 +1,114 @@
|
||||
package net.md_5.bungee.config;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
public class JsonConfiguration extends ConfigurationProvider
|
||||
{
|
||||
|
||||
private final Gson json = new GsonBuilder().serializeNulls().setPrettyPrinting().registerTypeAdapter( Configuration.class, new JsonSerializer<Configuration>()
|
||||
{
|
||||
@Override
|
||||
public JsonElement serialize(Configuration src, Type typeOfSrc, JsonSerializationContext context)
|
||||
{
|
||||
return context.serialize( ( (Configuration) src ).self );
|
||||
}
|
||||
} ).create();
|
||||
|
||||
@Override
|
||||
public void save(Configuration config, File file) throws IOException
|
||||
{
|
||||
try ( Writer writer = new OutputStreamWriter( new FileOutputStream( file ), Charsets.UTF_8 ) )
|
||||
{
|
||||
save( config, writer );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(Configuration config, Writer writer)
|
||||
{
|
||||
json.toJson( config.self, writer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration load(File file) throws IOException
|
||||
{
|
||||
return load( file, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration load(File file, Configuration defaults) throws IOException
|
||||
{
|
||||
try ( FileInputStream is = new FileInputStream( file ) )
|
||||
{
|
||||
return load( is, defaults );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration load(Reader reader)
|
||||
{
|
||||
return load( reader, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Configuration load(Reader reader, Configuration defaults)
|
||||
{
|
||||
Map<String, Object> map = json.fromJson( reader, LinkedHashMap.class );
|
||||
if ( map == null )
|
||||
{
|
||||
map = new LinkedHashMap<>();
|
||||
}
|
||||
return new Configuration( map, defaults );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration load(InputStream is)
|
||||
{
|
||||
return load( is, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration load(InputStream is, Configuration defaults)
|
||||
{
|
||||
return load( new InputStreamReader( is, Charsets.UTF_8 ), defaults );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration load(String string)
|
||||
{
|
||||
return load( string, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Configuration load(String string, Configuration defaults)
|
||||
{
|
||||
Map<String, Object> map = json.fromJson( string, LinkedHashMap.class );
|
||||
if ( map == null )
|
||||
{
|
||||
map = new LinkedHashMap<>();
|
||||
}
|
||||
return new Configuration( map, defaults );
|
||||
}
|
||||
}
|
@ -0,0 +1,229 @@
|
||||
package net.md_5.bungee.config;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@RunWith(Parameterized.class)
|
||||
public class CompoundConfigurationTest
|
||||
{
|
||||
|
||||
@Parameters(name = "{0}")
|
||||
public static Iterable<Object[]> data()
|
||||
{
|
||||
// CHECKSTYLE:OFF
|
||||
return Arrays.asList( new Object[][]
|
||||
{
|
||||
{
|
||||
// provider
|
||||
YamlConfiguration.class,
|
||||
// testDocument
|
||||
""
|
||||
+ "receipt: Oz-Ware Purchase Invoice\n"
|
||||
+ "date: 2012-08-06\n"
|
||||
+ "customer:\n"
|
||||
+ " given: Dorothy\n"
|
||||
+ " family: Gale\n"
|
||||
+ "\n"
|
||||
+ "items:\n"
|
||||
+ " - part_no: A4786\n"
|
||||
+ " descrip: Water Bucket (Filled)\n"
|
||||
+ " price: 1.47\n"
|
||||
+ " quantity: 4\n"
|
||||
+ "\n"
|
||||
+ " - part_no: E1628\n"
|
||||
+ " descrip: High Heeled \"Ruby\" Slippers\n"
|
||||
+ " size: 8\n"
|
||||
+ " price: 100.27\n"
|
||||
+ " quantity: 1\n"
|
||||
+ "\n"
|
||||
+ "bill-to: &id001\n"
|
||||
+ " street: |\n"
|
||||
+ " 123 Tornado Alley\n"
|
||||
+ " Suite 16\n"
|
||||
+ " city: East Centerville\n"
|
||||
+ " state: KS\n"
|
||||
+ "\n"
|
||||
+ "ship-to: *id001\n"
|
||||
+ "\n"
|
||||
+ "specialDelivery: >\n"
|
||||
+ " Follow the Yellow Brick\n"
|
||||
+ " Road to the Emerald City.\n"
|
||||
+ " Pay no attention to the\n"
|
||||
+ " man behind the curtain.",
|
||||
// numberTest
|
||||
""
|
||||
+ "someKey:\n"
|
||||
+ " 1: 1\n"
|
||||
+ " 2: 2\n"
|
||||
+ " 3: 3\n"
|
||||
+ " 4: 4",
|
||||
// nullTest
|
||||
""
|
||||
+ "null:\n"
|
||||
+ " null: object\n"
|
||||
+ " object: null\n"
|
||||
},
|
||||
{
|
||||
// provider
|
||||
JsonConfiguration.class,
|
||||
// testDocument
|
||||
""
|
||||
+ "{\n"
|
||||
+ " \"customer\": {\n"
|
||||
+ " \"given\": \"Dorothy\", \n"
|
||||
+ " \"family\": \"Gale\"\n"
|
||||
+ " }, \n"
|
||||
+ " \"ship-to\": {\n"
|
||||
+ " \"city\": \"East Centerville\", \n"
|
||||
+ " \"state\": \"KS\", \n"
|
||||
+ " \"street\": \"123 Tornado Alley\\nSuite 16\\n\"\n"
|
||||
+ " }, \n"
|
||||
+ " \"bill-to\": {\n"
|
||||
+ " \"city\": \"East Centerville\", \n"
|
||||
+ " \"state\": \"KS\", \n"
|
||||
+ " \"street\": \"123 Tornado Alley\\nSuite 16\\n\"\n"
|
||||
+ " }, \n"
|
||||
+ " \"date\": \"2012-08-06\", \n"
|
||||
+ " \"items\": [\n"
|
||||
+ " {\n"
|
||||
+ " \"part_no\": \"A4786\", \n"
|
||||
+ " \"price\": 1.47, \n"
|
||||
+ " \"descrip\": \"Water Bucket (Filled)\", \n"
|
||||
+ " \"quantity\": 4\n"
|
||||
+ " }, \n"
|
||||
+ " {\n"
|
||||
+ " \"part_no\": \"E1628\", \n"
|
||||
+ " \"descrip\": \"High Heeled \\\"Ruby\\\" Slippers\", \n"
|
||||
+ " \"price\": 100.27, \n"
|
||||
+ " \"quantity\": 1, \n"
|
||||
+ " \"size\": 8\n"
|
||||
+ " }\n"
|
||||
+ " ], \n"
|
||||
+ " \"receipt\": \"Oz-Ware Purchase Invoice\", \n"
|
||||
+ " \"specialDelivery\": \"Follow the Yellow Brick Road to the Emerald City. Pay no attention to the man behind the curtain.\"\n"
|
||||
+ "}",
|
||||
// numberTest
|
||||
""
|
||||
+ "{\n"
|
||||
+ " \"someKey\": {\n"
|
||||
+ " \"1\": 1, \n"
|
||||
+ " \"2\": 2, \n"
|
||||
+ " \"3\": 3, \n"
|
||||
+ " \"4\": 4\n"
|
||||
+ " }\n"
|
||||
+ "}",
|
||||
// nullTest
|
||||
""
|
||||
+ "{\n"
|
||||
+ " \"null\": {\n"
|
||||
+ " \"null\": \"object\", \n"
|
||||
+ " \"object\": null\n"
|
||||
+ " }\n"
|
||||
+ "}"
|
||||
}
|
||||
} );
|
||||
// CHECKSTYLE:ON
|
||||
}
|
||||
//
|
||||
private final Class<? extends ConfigurationProvider> provider;
|
||||
private final String testDocument;
|
||||
private final String numberTest;
|
||||
private final String nullTest;
|
||||
|
||||
@Test
|
||||
public void testConfig() throws Exception
|
||||
{
|
||||
Configuration conf = ConfigurationProvider.getProvider( provider ).load( testDocument );
|
||||
testSection( conf );
|
||||
|
||||
StringWriter sw = new StringWriter();
|
||||
ConfigurationProvider.getProvider( provider ).save( conf, sw );
|
||||
|
||||
// Check nulls were saved, see #1094
|
||||
Assert.assertFalse( "Config contains null", sw.toString().contains( "null" ) );
|
||||
|
||||
conf = ConfigurationProvider.getProvider( provider ).load( new StringReader( sw.toString() ) );
|
||||
conf.set( "receipt", "Oz-Ware Purchase Invoice" ); // Add it back
|
||||
testSection( conf );
|
||||
}
|
||||
|
||||
private void testSection(Configuration conf)
|
||||
{
|
||||
Assert.assertEquals( "receipt", "Oz-Ware Purchase Invoice", conf.getString( "receipt" ) );
|
||||
// Assert.assertEquals( "date", "2012-08-06", conf.get( "date" ).toString() );
|
||||
|
||||
Configuration customer = conf.getSection( "customer" );
|
||||
Assert.assertEquals( "customer.given", "Dorothy", customer.getString( "given" ) );
|
||||
Assert.assertEquals( "customer.given", "Dorothy", conf.getString( "customer.given" ) );
|
||||
|
||||
List items = conf.getList( "items" );
|
||||
Map item = (Map) items.get( 0 );
|
||||
Assert.assertEquals( "items[0].part_no", "A4786", item.get( "part_no" ) );
|
||||
|
||||
conf.set( "receipt", null );
|
||||
Assert.assertEquals( null, conf.get( "receipt" ) );
|
||||
Assert.assertEquals( "foo", conf.get( "receipt", "foo" ) );
|
||||
|
||||
Configuration newSection = conf.getSection( "new.section" );
|
||||
newSection.set( "value", "foo" );
|
||||
Assert.assertEquals( "foo", conf.get( "new.section.value" ) );
|
||||
|
||||
conf.set( "other.new.section", "bar" );
|
||||
Assert.assertEquals( "bar", conf.get( "other.new.section" ) );
|
||||
|
||||
Assert.assertTrue( conf.contains( "customer.given" ) );
|
||||
Assert.assertTrue( customer.contains( "given" ) );
|
||||
|
||||
Assert.assertFalse( conf.contains( "customer.foo" ) );
|
||||
Assert.assertFalse( customer.contains( "foo" ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumberedKeys()
|
||||
{
|
||||
Configuration conf = ConfigurationProvider.getProvider( provider ).load( numberTest );
|
||||
|
||||
Configuration section = conf.getSection( "someKey" );
|
||||
for ( String key : section.getKeys() )
|
||||
{
|
||||
// empty
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNull()
|
||||
{
|
||||
Configuration conf = ConfigurationProvider.getProvider( provider ).load( nullTest );
|
||||
|
||||
Assert.assertEquals( "object", conf.get( "null.null" ) );
|
||||
Assert.assertEquals( "object", conf.getSection( "null" ).get( "null" ) );
|
||||
|
||||
Assert.assertEquals( null, conf.get( "null.object" ) );
|
||||
Assert.assertEquals( "", conf.getString( "null.object" ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapAddition()
|
||||
{
|
||||
Configuration conf = ConfigurationProvider.getProvider( provider ).load( testDocument );
|
||||
|
||||
conf.set( "addition", Collections.singletonMap( "foo", "bar" ) );
|
||||
|
||||
// Order matters
|
||||
Assert.assertEquals( "bar", conf.getSection( "addition" ).getString( "foo" ) );
|
||||
Assert.assertEquals( "bar", conf.getString( "addition.foo" ) );
|
||||
|
||||
Assert.assertTrue( conf.get( "addition" ) instanceof Configuration );
|
||||
}
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
package net.md_5.bungee.config;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class YamlConfigurationTest
|
||||
{
|
||||
|
||||
private static final String TEST_DOCUMENT = ""
|
||||
+ "receipt: Oz-Ware Purchase Invoice\n"
|
||||
+ "date: 2012-08-06\n"
|
||||
+ "customer:\n"
|
||||
+ " given: Dorothy\n"
|
||||
+ " family: Gale\n"
|
||||
+ "\n"
|
||||
+ "items:\n"
|
||||
+ " - part_no: A4786\n"
|
||||
+ " descrip: Water Bucket (Filled)\n"
|
||||
+ " price: 1.47\n"
|
||||
+ " quantity: 4\n"
|
||||
+ "\n"
|
||||
+ " - part_no: E1628\n"
|
||||
+ " descrip: High Heeled \"Ruby\" Slippers\n"
|
||||
+ " size: 8\n"
|
||||
+ " price: 100.27\n"
|
||||
+ " quantity: 1\n"
|
||||
+ "\n"
|
||||
+ "bill-to: &id001\n"
|
||||
+ " street: |\n"
|
||||
+ " 123 Tornado Alley\n"
|
||||
+ " Suite 16\n"
|
||||
+ " city: East Centerville\n"
|
||||
+ " state: KS\n"
|
||||
+ "\n"
|
||||
+ "ship-to: *id001\n"
|
||||
+ "\n"
|
||||
+ "specialDelivery: >\n"
|
||||
+ " Follow the Yellow Brick\n"
|
||||
+ " Road to the Emerald City.\n"
|
||||
+ " Pay no attention to the\n"
|
||||
+ " man behind the curtain.";
|
||||
private static final String NUMBER_TEST = ""
|
||||
+ "someKey:\n"
|
||||
+ " 1: 1\n"
|
||||
+ " 2: 2\n"
|
||||
+ " 3: 3\n"
|
||||
+ " 4: 4";
|
||||
private static final String NULL_TEST = ""
|
||||
+ "null:\n"
|
||||
+ " null: object\n"
|
||||
+ " object: null\n";
|
||||
|
||||
@Test
|
||||
public void testConfig() throws Exception
|
||||
{
|
||||
Configuration conf = ConfigurationProvider.getProvider( YamlConfiguration.class ).load( TEST_DOCUMENT );
|
||||
testSection( conf );
|
||||
|
||||
StringWriter sw = new StringWriter();
|
||||
ConfigurationProvider.getProvider( YamlConfiguration.class ).save( conf, sw );
|
||||
|
||||
// Check nulls were saved, see #1094
|
||||
Assert.assertFalse( "Config contains null", sw.toString().contains( "null" ) );
|
||||
|
||||
conf = ConfigurationProvider.getProvider( YamlConfiguration.class ).load( new StringReader( sw.toString() ) );
|
||||
conf.set( "receipt", "Oz-Ware Purchase Invoice" ); // Add it back
|
||||
testSection( conf );
|
||||
}
|
||||
|
||||
private void testSection(Configuration conf)
|
||||
{
|
||||
Assert.assertEquals( "receipt", "Oz-Ware Purchase Invoice", conf.getString( "receipt" ) );
|
||||
// Assert.assertEquals( "date", "2012-08-06", conf.get( "date" ).toString() );
|
||||
|
||||
Configuration customer = conf.getSection( "customer" );
|
||||
Assert.assertEquals( "customer.given", "Dorothy", customer.getString( "given" ) );
|
||||
Assert.assertEquals( "customer.given", "Dorothy", conf.getString( "customer.given" ) );
|
||||
|
||||
List items = conf.getList( "items" );
|
||||
Map item = (Map) items.get( 0 );
|
||||
Assert.assertEquals( "items[0].part_no", "A4786", item.get( "part_no" ) );
|
||||
|
||||
conf.set( "receipt", null );
|
||||
Assert.assertEquals( null, conf.get( "receipt" ) );
|
||||
Assert.assertEquals( "foo", conf.get( "receipt", "foo" ) );
|
||||
|
||||
Configuration newSection = conf.getSection( "new.section" );
|
||||
newSection.set( "value", "foo" );
|
||||
Assert.assertEquals( "foo", conf.get( "new.section.value" ) );
|
||||
|
||||
conf.set( "other.new.section", "bar" );
|
||||
Assert.assertEquals( "bar", conf.get( "other.new.section" ) );
|
||||
|
||||
Assert.assertTrue( conf.contains( "customer.given" ) );
|
||||
Assert.assertTrue( customer.contains( "given" ) );
|
||||
|
||||
Assert.assertFalse( conf.contains( "customer.foo" ) );
|
||||
Assert.assertFalse( customer.contains( "foo" ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumberedKeys()
|
||||
{
|
||||
Configuration conf = ConfigurationProvider.getProvider( YamlConfiguration.class ).load( NUMBER_TEST );
|
||||
|
||||
Configuration section = conf.getSection( "someKey" );
|
||||
for ( String key : section.getKeys() )
|
||||
{
|
||||
// empty
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNull()
|
||||
{
|
||||
Configuration conf = ConfigurationProvider.getProvider( YamlConfiguration.class ).load( NULL_TEST );
|
||||
|
||||
Assert.assertEquals( "object", conf.get( "null.null" ) );
|
||||
Assert.assertEquals( "object", conf.getSection( "null" ).get( "null" ) );
|
||||
|
||||
Assert.assertEquals( null, conf.get( "null.object" ) );
|
||||
Assert.assertEquals( "", conf.getString( "null.object" ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapAddition()
|
||||
{
|
||||
Configuration conf = ConfigurationProvider.getProvider( YamlConfiguration.class ).load( TEST_DOCUMENT );
|
||||
|
||||
conf.set( "addition", Collections.singletonMap( "foo", "bar" ) );
|
||||
|
||||
// Order matters
|
||||
Assert.assertEquals( "bar", conf.getSection( "addition" ).getString( "foo" ) );
|
||||
Assert.assertEquals( "bar", conf.getString( "addition.foo" ) );
|
||||
|
||||
Assert.assertTrue( conf.get( "addition" ) instanceof Configuration );
|
||||
}
|
||||
}
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-event</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-Event</name>
|
||||
|
@ -166,6 +166,8 @@ public class EventBus
|
||||
* 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)}.
|
||||
*
|
||||
* @param eventClass event class
|
||||
*/
|
||||
private void bakeHandlers(Class<?> eventClass)
|
||||
{
|
||||
|
@ -21,6 +21,8 @@ public @interface EventHandler
|
||||
* <li>HIGH</li>
|
||||
* <li>HIGHEST</li>
|
||||
* </ol>
|
||||
*
|
||||
* @return handler priority
|
||||
*/
|
||||
byte priority() default EventPriority.NORMAL;
|
||||
}
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-log</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-Log</name>
|
||||
|
@ -3,7 +3,6 @@ package net.md_5.bungee.log;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.FileHandler;
|
||||
import java.util.logging.Formatter;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.Logger;
|
||||
@ -12,7 +11,6 @@ import jline.console.ConsoleReader;
|
||||
public class BungeeLogger extends Logger
|
||||
{
|
||||
|
||||
private final Formatter formatter = new ConciseFormatter();
|
||||
private final LogDispatcher dispatcher = new LogDispatcher( this );
|
||||
|
||||
@SuppressWarnings(
|
||||
@ -28,12 +26,12 @@ public class BungeeLogger extends Logger
|
||||
try
|
||||
{
|
||||
FileHandler fileHandler = new FileHandler( filePattern, 1 << 24, 8, true );
|
||||
fileHandler.setFormatter( formatter );
|
||||
fileHandler.setFormatter( new ConciseFormatter( false ) );
|
||||
addHandler( fileHandler );
|
||||
|
||||
ColouredWriter consoleHandler = new ColouredWriter( reader );
|
||||
consoleHandler.setLevel( Level.INFO );
|
||||
consoleHandler.setFormatter( formatter );
|
||||
consoleHandler.setLevel( Level.parse( System.getProperty( "net.md_5.bungee.console-log-level", "INFO" ) ) );
|
||||
consoleHandler.setFormatter( new ConciseFormatter( true ) );
|
||||
addHandler( consoleHandler );
|
||||
} catch ( IOException ex )
|
||||
{
|
||||
|
@ -1,11 +1,11 @@
|
||||
package net.md_5.bungee.log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.regex.Pattern;
|
||||
import jline.console.ConsoleReader;
|
||||
import lombok.Data;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
import org.fusesource.jansi.Ansi.Erase;
|
||||
@ -13,43 +13,57 @@ import org.fusesource.jansi.Ansi.Erase;
|
||||
public class ColouredWriter extends Handler
|
||||
{
|
||||
|
||||
private final Map<ChatColor, String> replacements = new EnumMap<>( ChatColor.class );
|
||||
private final ChatColor[] colors = ChatColor.values();
|
||||
@Data
|
||||
private static class ReplacementSpecification
|
||||
{
|
||||
|
||||
private final Pattern pattern;
|
||||
private final String replacement;
|
||||
}
|
||||
|
||||
private static ReplacementSpecification compile(ChatColor color, String ansi)
|
||||
{
|
||||
return new ReplacementSpecification( Pattern.compile( "(?i)" + color.toString() ), ansi );
|
||||
}
|
||||
|
||||
private static final ReplacementSpecification[] REPLACEMENTS = new ReplacementSpecification[]
|
||||
{
|
||||
compile( ChatColor.BLACK, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.BLACK ).boldOff().toString() ),
|
||||
compile( ChatColor.DARK_BLUE, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.BLUE ).boldOff().toString() ),
|
||||
compile( ChatColor.DARK_GREEN, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.GREEN ).boldOff().toString() ),
|
||||
compile( ChatColor.DARK_AQUA, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.CYAN ).boldOff().toString() ),
|
||||
compile( ChatColor.DARK_RED, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.RED ).boldOff().toString() ),
|
||||
compile( ChatColor.DARK_PURPLE, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.MAGENTA ).boldOff().toString() ),
|
||||
compile( ChatColor.GOLD, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.YELLOW ).boldOff().toString() ),
|
||||
compile( ChatColor.GRAY, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.WHITE ).boldOff().toString() ),
|
||||
compile( ChatColor.DARK_GRAY, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.BLACK ).bold().toString() ),
|
||||
compile( ChatColor.BLUE, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.BLUE ).bold().toString() ),
|
||||
compile( ChatColor.GREEN, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.GREEN ).bold().toString() ),
|
||||
compile( ChatColor.AQUA, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.CYAN ).bold().toString() ),
|
||||
compile( ChatColor.RED, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.RED ).bold().toString() ),
|
||||
compile( ChatColor.LIGHT_PURPLE, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.MAGENTA ).bold().toString() ),
|
||||
compile( ChatColor.YELLOW, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.YELLOW ).bold().toString() ),
|
||||
compile( ChatColor.WHITE, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.WHITE ).bold().toString() ),
|
||||
compile( ChatColor.MAGIC, Ansi.ansi().a( Ansi.Attribute.BLINK_SLOW ).toString() ),
|
||||
compile( ChatColor.BOLD, Ansi.ansi().a( Ansi.Attribute.UNDERLINE_DOUBLE ).toString() ),
|
||||
compile( ChatColor.STRIKETHROUGH, Ansi.ansi().a( Ansi.Attribute.STRIKETHROUGH_ON ).toString() ),
|
||||
compile( ChatColor.UNDERLINE, Ansi.ansi().a( Ansi.Attribute.UNDERLINE ).toString() ),
|
||||
compile( ChatColor.ITALIC, Ansi.ansi().a( Ansi.Attribute.ITALIC ).toString() ),
|
||||
compile( ChatColor.RESET, Ansi.ansi().a( Ansi.Attribute.RESET ).toString() ),
|
||||
};
|
||||
//
|
||||
private final ConsoleReader console;
|
||||
|
||||
public ColouredWriter(ConsoleReader console)
|
||||
{
|
||||
this.console = console;
|
||||
|
||||
replacements.put( ChatColor.BLACK, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.BLACK ).boldOff().toString() );
|
||||
replacements.put( ChatColor.DARK_BLUE, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.BLUE ).boldOff().toString() );
|
||||
replacements.put( ChatColor.DARK_GREEN, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.GREEN ).boldOff().toString() );
|
||||
replacements.put( ChatColor.DARK_AQUA, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.CYAN ).boldOff().toString() );
|
||||
replacements.put( ChatColor.DARK_RED, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.RED ).boldOff().toString() );
|
||||
replacements.put( ChatColor.DARK_PURPLE, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.MAGENTA ).boldOff().toString() );
|
||||
replacements.put( ChatColor.GOLD, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.YELLOW ).boldOff().toString() );
|
||||
replacements.put( ChatColor.GRAY, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.WHITE ).boldOff().toString() );
|
||||
replacements.put( ChatColor.DARK_GRAY, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.BLACK ).bold().toString() );
|
||||
replacements.put( ChatColor.BLUE, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.BLUE ).bold().toString() );
|
||||
replacements.put( ChatColor.GREEN, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.GREEN ).bold().toString() );
|
||||
replacements.put( ChatColor.AQUA, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.CYAN ).bold().toString() );
|
||||
replacements.put( ChatColor.RED, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.RED ).bold().toString() );
|
||||
replacements.put( ChatColor.LIGHT_PURPLE, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.MAGENTA ).bold().toString() );
|
||||
replacements.put( ChatColor.YELLOW, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.YELLOW ).bold().toString() );
|
||||
replacements.put( ChatColor.WHITE, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.WHITE ).bold().toString() );
|
||||
replacements.put( ChatColor.MAGIC, Ansi.ansi().a( Ansi.Attribute.BLINK_SLOW ).toString() );
|
||||
replacements.put( ChatColor.BOLD, Ansi.ansi().a( Ansi.Attribute.UNDERLINE_DOUBLE ).toString() );
|
||||
replacements.put( ChatColor.STRIKETHROUGH, Ansi.ansi().a( Ansi.Attribute.STRIKETHROUGH_ON ).toString() );
|
||||
replacements.put( ChatColor.UNDERLINE, Ansi.ansi().a( Ansi.Attribute.UNDERLINE ).toString() );
|
||||
replacements.put( ChatColor.ITALIC, Ansi.ansi().a( Ansi.Attribute.ITALIC ).toString() );
|
||||
replacements.put( ChatColor.RESET, Ansi.ansi().a( Ansi.Attribute.RESET ).toString() );
|
||||
}
|
||||
|
||||
public void print(String s)
|
||||
{
|
||||
for ( ChatColor color : colors )
|
||||
for ( ReplacementSpecification replacement : REPLACEMENTS )
|
||||
{
|
||||
s = s.replaceAll( "(?i)" + color.toString(), replacements.get( color ) );
|
||||
s = replacement.pattern.matcher( s ).replaceAll( replacement.replacement );
|
||||
}
|
||||
try
|
||||
{
|
||||
|
@ -5,12 +5,17 @@ import java.io.StringWriter;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.logging.Formatter;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class ConciseFormatter extends Formatter
|
||||
{
|
||||
|
||||
private final DateFormat date = new SimpleDateFormat( System.getProperty( "net.md_5.bungee.log-date-format", "HH:mm:ss" ) );
|
||||
private final boolean coloured;
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("ThrowableResultIgnored")
|
||||
@ -20,7 +25,7 @@ public class ConciseFormatter extends Formatter
|
||||
|
||||
formatted.append( date.format( record.getMillis() ) );
|
||||
formatted.append( " [" );
|
||||
formatted.append( record.getLevel().getLocalizedName() );
|
||||
appendLevel( formatted, record.getLevel() );
|
||||
formatted.append( "] " );
|
||||
formatted.append( formatMessage( record ) );
|
||||
formatted.append( '\n' );
|
||||
@ -34,4 +39,31 @@ public class ConciseFormatter extends Formatter
|
||||
|
||||
return formatted.toString();
|
||||
}
|
||||
|
||||
private void appendLevel(StringBuilder builder, Level level)
|
||||
{
|
||||
if ( !coloured )
|
||||
{
|
||||
builder.append( level.getLocalizedName() );
|
||||
return;
|
||||
}
|
||||
|
||||
ChatColor color;
|
||||
|
||||
if ( level == Level.INFO )
|
||||
{
|
||||
color = ChatColor.BLUE;
|
||||
} else if ( level == Level.WARNING )
|
||||
{
|
||||
color = ChatColor.YELLOW;
|
||||
} else if ( level == Level.SEVERE )
|
||||
{
|
||||
color = ChatColor.RED;
|
||||
} else
|
||||
{
|
||||
color = ChatColor.AQUA;
|
||||
}
|
||||
|
||||
builder.append( color ).append( level.getLocalizedName() ).append( ChatColor.RESET );
|
||||
}
|
||||
}
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module-cmd-alert</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>cmd_alert</name>
|
||||
|
@ -19,7 +19,7 @@ public class CommandAlert extends Command
|
||||
{
|
||||
if ( args.length == 0 )
|
||||
{
|
||||
sender.sendMessage( ChatColor.RED + "You must supply a message." );
|
||||
sender.sendMessage( ProxyServer.getInstance().getTranslation( "message_needed" ) );
|
||||
} else
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
@ -23,7 +23,7 @@ public class CommandAlertRaw extends Command
|
||||
{
|
||||
if ( args.length == 0 )
|
||||
{
|
||||
sender.sendMessage( ChatColor.RED + "You must supply a message." );
|
||||
sender.sendMessage( ProxyServer.getInstance().getTranslation( "message_needed" ) );
|
||||
} else
|
||||
{
|
||||
String message = Joiner.on( ' ' ).join( args );
|
||||
@ -40,15 +40,15 @@ public class CommandAlertRaw extends Command
|
||||
}
|
||||
if ( sender instanceof ProxiedPlayer )
|
||||
{
|
||||
sender.sendMessage( new ComponentBuilder( "An error occurred while parsing your message. (Hover for details)" )
|
||||
.color( ChatColor.RED )
|
||||
.underlined( true )
|
||||
.event( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( error.getMessage() ).color( ChatColor.RED ).create() ) )
|
||||
sender.sendMessage( new ComponentBuilder( ProxyServer.getInstance().getTranslation( "error_occurred_player" ) )
|
||||
.event( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( error.getMessage() )
|
||||
.color( ChatColor.RED )
|
||||
.create() ) )
|
||||
.create()
|
||||
);
|
||||
} else
|
||||
{
|
||||
sender.sendMessage( new ComponentBuilder( "An error occurred while parsing your message: " ).color( ChatColor.RED ).append( error.getMessage() ).create() );
|
||||
sender.sendMessage( ProxyServer.getInstance().getTranslation( "error_occurred_console", error.getMessage() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module-cmd-find</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>cmd_find</name>
|
||||
|
@ -1,9 +1,7 @@
|
||||
package net.md_5.bungee.module.cmd.find;
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.command.PlayerCommand;
|
||||
|
||||
@ -20,16 +18,16 @@ public class CommandFind extends PlayerCommand
|
||||
{
|
||||
if ( args.length != 1 )
|
||||
{
|
||||
sender.sendMessage( new ComponentBuilder( "Please follow this command by a user name" ).color( ChatColor.RED ).create() );
|
||||
sender.sendMessage( ProxyServer.getInstance().getTranslation( "username_needed" ) );
|
||||
} else
|
||||
{
|
||||
ProxiedPlayer player = ProxyServer.getInstance().getPlayer( args[0] );
|
||||
if ( player == null || player.getServer() == null )
|
||||
{
|
||||
sender.sendMessage( new ComponentBuilder( "That user is not online" ).color( ChatColor.RED ).create() );
|
||||
sender.sendMessage( ProxyServer.getInstance().getTranslation( "user_not_online" ) );
|
||||
} else
|
||||
{
|
||||
sender.sendMessage( new ComponentBuilder( args[0] ).color( ChatColor.GREEN ).append( " is online at " ).append( player.getServer().getInfo().getName() ).create() );
|
||||
sender.sendMessage( ProxyServer.getInstance().getTranslation( "user_online_at", player.getName(), player.getServer().getInfo().getName() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module-cmd-list</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>cmd_list</name>
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module-cmd-send</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>cmd_send</name>
|
||||
|
@ -1,12 +1,22 @@
|
||||
package net.md_5.bungee.module.cmd.send;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import net.md_5.bungee.api.Callback;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.ServerConnectRequest;
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||
import net.md_5.bungee.api.chat.HoverEvent;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.ServerConnectEvent;
|
||||
@ -16,6 +26,71 @@ import net.md_5.bungee.api.plugin.TabExecutor;
|
||||
public class CommandSend extends Command implements TabExecutor
|
||||
{
|
||||
|
||||
protected static class SendCallback
|
||||
{
|
||||
|
||||
private final Map<ServerConnectRequest.Result, List<String>> results = new HashMap<>();
|
||||
private final CommandSender sender;
|
||||
private int count = 0;
|
||||
|
||||
public SendCallback(CommandSender sender)
|
||||
{
|
||||
this.sender = sender;
|
||||
for ( ServerConnectRequest.Result result : ServerConnectRequest.Result.values() )
|
||||
{
|
||||
results.put( result, new ArrayList<String>() );
|
||||
}
|
||||
}
|
||||
|
||||
public void lastEntryDone()
|
||||
{
|
||||
sender.sendMessage( ChatColor.GREEN.toString() + ChatColor.BOLD + "Send Results:" );
|
||||
for ( Map.Entry<ServerConnectRequest.Result, List<String>> entry : results.entrySet() )
|
||||
{
|
||||
ComponentBuilder builder = new ComponentBuilder( "" );
|
||||
if ( !entry.getValue().isEmpty() )
|
||||
{
|
||||
builder.event( new HoverEvent( HoverEvent.Action.SHOW_TEXT,
|
||||
new ComponentBuilder( Joiner.on( ", " ).join( entry.getValue() ) ).color( ChatColor.YELLOW ).create() ) );
|
||||
}
|
||||
builder.append( entry.getKey().name() + ": " ).color( ChatColor.GREEN );
|
||||
builder.append( "" + entry.getValue().size() ).bold( true );
|
||||
sender.sendMessage( builder.create() );
|
||||
}
|
||||
}
|
||||
|
||||
public static class Entry implements Callback<ServerConnectRequest.Result>
|
||||
{
|
||||
|
||||
private final SendCallback callback;
|
||||
private final ProxiedPlayer player;
|
||||
private final ServerInfo target;
|
||||
|
||||
public Entry(SendCallback callback, ProxiedPlayer player, ServerInfo target)
|
||||
{
|
||||
this.callback = callback;
|
||||
this.player = player;
|
||||
this.target = target;
|
||||
this.callback.count++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void done(ServerConnectRequest.Result result, Throwable error)
|
||||
{
|
||||
callback.results.get( result ).add( player.getName() );
|
||||
if ( result == ServerConnectRequest.Result.SUCCESS )
|
||||
{
|
||||
player.sendMessage( ProxyServer.getInstance().getTranslation( "you_got_summoned", target.getName(), callback.sender.getName() ) );
|
||||
}
|
||||
|
||||
if ( --callback.count == 0 )
|
||||
{
|
||||
callback.lastEntryDone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CommandSend()
|
||||
{
|
||||
super( "send", "bungeecord.command.send" );
|
||||
@ -26,65 +101,60 @@ public class CommandSend extends Command implements TabExecutor
|
||||
{
|
||||
if ( args.length != 2 )
|
||||
{
|
||||
sender.sendMessage( ChatColor.RED + "Not enough arguments, usage: /send <server|player|all|current> <target>" );
|
||||
sender.sendMessage( ProxyServer.getInstance().getTranslation( "send_cmd_usage" ) );
|
||||
return;
|
||||
}
|
||||
ServerInfo target = ProxyServer.getInstance().getServerInfo( args[1] );
|
||||
if ( target == null )
|
||||
ServerInfo server = ProxyServer.getInstance().getServerInfo( args[1] );
|
||||
if ( server == null )
|
||||
{
|
||||
sender.sendMessage( ProxyServer.getInstance().getTranslation( "no_server" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
List<ProxiedPlayer> targets;
|
||||
if ( args[0].equalsIgnoreCase( "all" ) )
|
||||
{
|
||||
for ( ProxiedPlayer p : ProxyServer.getInstance().getPlayers() )
|
||||
{
|
||||
summon( p, target, sender );
|
||||
}
|
||||
targets = new ArrayList<>( ProxyServer.getInstance().getPlayers() );
|
||||
} else if ( args[0].equalsIgnoreCase( "current" ) )
|
||||
{
|
||||
if ( !( sender instanceof ProxiedPlayer ) )
|
||||
{
|
||||
sender.sendMessage( ChatColor.RED + "Only in game players can use this command" );
|
||||
sender.sendMessage( ProxyServer.getInstance().getTranslation( "player_only" ) );
|
||||
return;
|
||||
}
|
||||
ProxiedPlayer player = (ProxiedPlayer) sender;
|
||||
for ( ProxiedPlayer p : player.getServer().getInfo().getPlayers() )
|
||||
{
|
||||
summon( p, target, sender );
|
||||
}
|
||||
targets = new ArrayList<>( player.getServer().getInfo().getPlayers() );
|
||||
} else
|
||||
{
|
||||
// If we use a server name, send the entire server. This takes priority over players.
|
||||
ServerInfo serverTarget = ProxyServer.getInstance().getServerInfo( args[0] );
|
||||
if ( serverTarget != null )
|
||||
{
|
||||
for ( ProxiedPlayer p : serverTarget.getPlayers() )
|
||||
{
|
||||
summon( p, target, sender );
|
||||
}
|
||||
targets = new ArrayList<>( serverTarget.getPlayers() );
|
||||
} else
|
||||
{
|
||||
ProxiedPlayer player = ProxyServer.getInstance().getPlayer( args[0] );
|
||||
if ( player == null )
|
||||
{
|
||||
sender.sendMessage( ChatColor.RED + "That player is not online" );
|
||||
sender.sendMessage( ProxyServer.getInstance().getTranslation( "user_not_online" ) );
|
||||
return;
|
||||
}
|
||||
summon( player, target, sender );
|
||||
targets = Collections.singletonList( player );
|
||||
}
|
||||
}
|
||||
sender.sendMessage( ChatColor.GREEN + "Successfully summoned player(s)" );
|
||||
}
|
||||
|
||||
private void summon(ProxiedPlayer player, ServerInfo target, CommandSender sender)
|
||||
{
|
||||
if ( player.getServer() != null && !player.getServer().getInfo().equals( target ) )
|
||||
final SendCallback callback = new SendCallback( sender );
|
||||
for ( ProxiedPlayer player : targets )
|
||||
{
|
||||
player.connect( target, ServerConnectEvent.Reason.COMMAND );
|
||||
player.sendMessage( ChatColor.GOLD + "Summoned to " + target.getName() + " by " + sender.getName() );
|
||||
ServerConnectRequest request = ServerConnectRequest.builder()
|
||||
.target( server )
|
||||
.reason( ServerConnectEvent.Reason.COMMAND )
|
||||
.callback( new SendCallback.Entry( callback, player, server ) )
|
||||
.build();
|
||||
player.connect( request );
|
||||
}
|
||||
|
||||
sender.sendMessage( ChatColor.DARK_GREEN + "Attempting to send " + targets.size() + " players to " + server.getName() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module-cmd-server</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>cmd_server</name>
|
||||
|
@ -40,7 +40,7 @@ public class CommandServer extends Command implements TabExecutor
|
||||
sender.sendMessage( ProxyServer.getInstance().getTranslation( "current_server", ( (ProxiedPlayer) sender ).getServer().getInfo().getName() ) );
|
||||
}
|
||||
|
||||
ComponentBuilder serverList = new ComponentBuilder( "" ).append( TextComponent.fromLegacyText( ProxyServer.getInstance().getTranslation( "server_list" ) ) );
|
||||
ComponentBuilder serverList = new ComponentBuilder().appendLegacy( ProxyServer.getInstance().getTranslation( "server_list" ) );
|
||||
boolean first = true;
|
||||
for ( ServerInfo server : servers.values() )
|
||||
{
|
||||
@ -50,7 +50,7 @@ public class CommandServer extends Command implements TabExecutor
|
||||
int count = server.getPlayers().size();
|
||||
serverTextComponent.setHoverEvent( new HoverEvent(
|
||||
HoverEvent.Action.SHOW_TEXT,
|
||||
new ComponentBuilder( count + ( count == 1 ? " player" : " players" ) + "\n" ).append( "Click to connect to the server" ).italic( true ).create() )
|
||||
new ComponentBuilder( count + ( count == 1 ? " player" : " players" ) + "\n" ).appendLegacy( ProxyServer.getInstance().getTranslation( "click_to_connect" ) ).create() )
|
||||
);
|
||||
serverTextComponent.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, "/server " + server.getName() ) );
|
||||
serverList.append( serverTextComponent );
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>BungeeCord Modules</name>
|
||||
@ -30,6 +30,7 @@
|
||||
<properties>
|
||||
<module.author>SpigotMC</module.author>
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
<maven.javadoc.skip>true</maven.javadoc.skip>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module-reconnect-yaml</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>reconnect_yaml</name>
|
||||
|
@ -24,7 +24,7 @@ public class YamlReconnectHandler extends AbstractReconnectHandler
|
||||
private final File file = new File( "locations.yml" );
|
||||
private final ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
/*========================================================================*/
|
||||
private CaseInsensitiveMap< String> data;
|
||||
private CaseInsensitiveMap<String> data;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public YamlReconnectHandler()
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-native</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-Native</name>
|
||||
|
@ -28,8 +28,8 @@ public final class NativeCode<T>
|
||||
{
|
||||
try
|
||||
{
|
||||
return ( loaded ) ? nativeImpl.newInstance() : javaImpl.newInstance();
|
||||
} catch ( IllegalAccessException | InstantiationException ex )
|
||||
return ( loaded ) ? nativeImpl.getDeclaredConstructor().newInstance() : javaImpl.getDeclaredConstructor().newInstance();
|
||||
} catch ( ReflectiveOperationException ex )
|
||||
{
|
||||
throw new RuntimeException( "Error getting instance", ex );
|
||||
}
|
||||
|
@ -80,6 +80,9 @@ public class NativeCipherTest
|
||||
/**
|
||||
* Hackish test which can test both native and fallback ciphers using direct
|
||||
* buffers.
|
||||
*
|
||||
* @param cipher cipher to test
|
||||
* @throws java.lang.Exception any exceptions encountered
|
||||
*/
|
||||
public void testACipher(BungeeCipher cipher) throws Exception
|
||||
{
|
||||
|
129
pom.xml
129
pom.xml
@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>BungeeCord-Parent</name>
|
||||
@ -63,13 +63,17 @@
|
||||
<id>sonatype-nexus-snapshots</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
</snapshotRepository>
|
||||
<repository>
|
||||
<id>sonatype-nexus-staging</id>
|
||||
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
|
||||
<properties>
|
||||
<build.number>unknown</build.number>
|
||||
<netty.version>4.1.34.Final</netty.version>
|
||||
<maven.compiler.source>1.7</maven.compiler.source>
|
||||
<maven.compiler.target>1.7</maven.compiler.target>
|
||||
<netty.version>4.1.49.Final</netty.version>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
@ -77,13 +81,13 @@
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<version>4.13</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>20.0</version>
|
||||
<version>21.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@ -95,7 +99,7 @@
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.4</version>
|
||||
<version>1.18.10</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
@ -105,7 +109,7 @@
|
||||
<plugin>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>scriptus</artifactId>
|
||||
<version>0.3.1</version>
|
||||
<version>0.3.2</version>
|
||||
<configuration>
|
||||
<format>git:${project.name}:${project.version}:%s:${build.number}</format>
|
||||
</configuration>
|
||||
@ -121,7 +125,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>process-classes</phase>
|
||||
@ -139,14 +143,14 @@
|
||||
<dependency>
|
||||
<groupId>com.puppycrawl.tools</groupId>
|
||||
<artifactId>checkstyle</artifactId>
|
||||
<version>8.19</version>
|
||||
<version>8.29</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>animal-sniffer-maven-plugin</artifactId>
|
||||
<version>1.16</version>
|
||||
<version>1.18</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>process-classes</phase>
|
||||
@ -164,36 +168,77 @@
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
|
||||
<plugin>
|
||||
<groupId>org.eclipse.m2e</groupId>
|
||||
<artifactId>lifecycle-mapping</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<configuration>
|
||||
<lifecycleMappingMetadata>
|
||||
<pluginExecutions>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>scriptus</artifactId>
|
||||
<versionRange>[0.3.1,)</versionRange>
|
||||
<goals>
|
||||
<goal>describe</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<execute>
|
||||
<runOnIncremental>false</runOnIncremental>
|
||||
</execute>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
</pluginExecutions>
|
||||
</lifecycleMappingMetadata>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>dist</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>jar-no-fork</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok-maven-plugin</artifactId>
|
||||
<version>1.18.10.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>delombok</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<addOutputDirectory>false</addOutputDirectory>
|
||||
<outputDirectory>${project.build.directory}/delombok</outputDirectory>
|
||||
<sourceDirectory>${project.build.sourceDirectory}</sourceDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<executions>
|
||||
<!-- Execute Javadoc once normally to catch any warnings -->
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<!-- Then execute it again to generate properly with delombok -->
|
||||
<execution>
|
||||
<id>delombok</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<!-- lombok does not add @return or @param which causes warnings, so ignore -->
|
||||
<doclint>none</doclint>
|
||||
<sourcepath>${project.build.directory}/delombok</sourcepath>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<quiet>true</quiet>
|
||||
<failOnWarnings>true</failOnWarnings>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-protocol</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-Protocol</name>
|
||||
@ -58,5 +58,11 @@
|
||||
<version>3.1.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>se.llbit</groupId>
|
||||
<artifactId>jo-nbt</artifactId>
|
||||
<version>1.3.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
@ -8,6 +8,7 @@ import net.md_5.bungee.protocol.packet.Commands;
|
||||
import net.md_5.bungee.protocol.packet.EncryptionRequest;
|
||||
import net.md_5.bungee.protocol.packet.EncryptionResponse;
|
||||
import net.md_5.bungee.protocol.packet.EntityStatus;
|
||||
import net.md_5.bungee.protocol.packet.GameState;
|
||||
import net.md_5.bungee.protocol.packet.Handshake;
|
||||
import net.md_5.bungee.protocol.packet.KeepAlive;
|
||||
import net.md_5.bungee.protocol.packet.Kick;
|
||||
@ -173,4 +174,8 @@ public abstract class AbstractPacketHandler
|
||||
public void handle(ViewDistance viewDistance) throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
public void handle(GameState gameState) throws Exception
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import net.md_5.bungee.protocol.packet.Commands;
|
||||
import net.md_5.bungee.protocol.packet.EncryptionRequest;
|
||||
import net.md_5.bungee.protocol.packet.EncryptionResponse;
|
||||
import net.md_5.bungee.protocol.packet.EntityStatus;
|
||||
import net.md_5.bungee.protocol.packet.GameState;
|
||||
import net.md_5.bungee.protocol.packet.Handshake;
|
||||
import net.md_5.bungee.protocol.packet.KeepAlive;
|
||||
import net.md_5.bungee.protocol.packet.Kick;
|
||||
@ -65,19 +66,25 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_8, 0x00 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_9, 0x1F ),
|
||||
map( ProtocolConstants.MINECRAFT_1_13, 0x21 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x20 )
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x20 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_15, 0x21 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_16, 0x20 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
Login.class,
|
||||
map( ProtocolConstants.MINECRAFT_1_8, 0x01 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_9, 0x23 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_13, 0x25 )
|
||||
map( ProtocolConstants.MINECRAFT_1_13, 0x25 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_15, 0x26 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_16, 0x25 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
Chat.class,
|
||||
map( ProtocolConstants.MINECRAFT_1_8, 0x02 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_9, 0x0F ),
|
||||
map( ProtocolConstants.MINECRAFT_1_13, 0x0E )
|
||||
map( ProtocolConstants.MINECRAFT_1_13, 0x0E ),
|
||||
map( ProtocolConstants.MINECRAFT_1_15, 0x0F ),
|
||||
map( ProtocolConstants.MINECRAFT_1_16, 0x0E )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
Respawn.class,
|
||||
@ -86,11 +93,15 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_12, 0x34 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_12_1, 0x35 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_13, 0x38 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x3A )
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x3A ),
|
||||
map( ProtocolConstants.MINECRAFT_1_15, 0x3B ),
|
||||
map( ProtocolConstants.MINECRAFT_1_16, 0x3A )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
BossBar.class,
|
||||
map( ProtocolConstants.MINECRAFT_1_9, 0x0C )
|
||||
map( ProtocolConstants.MINECRAFT_1_9, 0x0C ),
|
||||
map( ProtocolConstants.MINECRAFT_1_15, 0x0D ),
|
||||
map( ProtocolConstants.MINECRAFT_1_16, 0x0C )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
PlayerListItem.class, // PlayerInfo
|
||||
@ -98,13 +109,17 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_9, 0x2D ),
|
||||
map( ProtocolConstants.MINECRAFT_1_12_1, 0x2E ),
|
||||
map( ProtocolConstants.MINECRAFT_1_13, 0x30 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x33 )
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x33 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_15, 0x34 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_16, 0x33 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
TabCompleteResponse.class,
|
||||
map( ProtocolConstants.MINECRAFT_1_8, 0x3A ),
|
||||
map( ProtocolConstants.MINECRAFT_1_9, 0x0E ),
|
||||
map( ProtocolConstants.MINECRAFT_1_13, 0x10 )
|
||||
map( ProtocolConstants.MINECRAFT_1_13, 0x10 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_15, 0x11 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_16, 0x10 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
ScoreboardObjective.class,
|
||||
@ -113,7 +128,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_12, 0x41 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_12_1, 0x42 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_13, 0x45 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x49 )
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x49 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_15, 0x4A )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
ScoreboardScore.class,
|
||||
@ -122,7 +138,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_12, 0x44 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_12_1, 0x45 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_13, 0x48 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x4C )
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x4C ),
|
||||
map( ProtocolConstants.MINECRAFT_1_15, 0x4D )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
ScoreboardDisplay.class,
|
||||
@ -131,7 +148,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_12, 0x3A ),
|
||||
map( ProtocolConstants.MINECRAFT_1_12_1, 0x3B ),
|
||||
map( ProtocolConstants.MINECRAFT_1_13, 0x3E ),
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x42 )
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x42 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_15, 0x43 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
Team.class,
|
||||
@ -140,21 +158,26 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_12, 0x43 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_12_1, 0x44 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_13, 0x47 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x4B )
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x4B ),
|
||||
map( ProtocolConstants.MINECRAFT_1_15, 0x4C )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
PluginMessage.class,
|
||||
map( ProtocolConstants.MINECRAFT_1_8, 0x3F ),
|
||||
map( ProtocolConstants.MINECRAFT_1_9, 0x18 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_13, 0x19 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x18 )
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x18 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_15, 0x19 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_16, 0x18 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
Kick.class,
|
||||
map( ProtocolConstants.MINECRAFT_1_8, 0x40 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_9, 0x1A ),
|
||||
map( ProtocolConstants.MINECRAFT_1_13, 0x1B ),
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x1A )
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x1A ),
|
||||
map( ProtocolConstants.MINECRAFT_1_15, 0x1B ),
|
||||
map( ProtocolConstants.MINECRAFT_1_16, 0x1A )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
Title.class,
|
||||
@ -162,7 +185,9 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_12, 0x47 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_12_1, 0x48 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_13, 0x4B ),
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x4F )
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x4F ),
|
||||
map( ProtocolConstants.MINECRAFT_1_15, 0x50 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_16, 0x4F )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
PlayerListHeaderFooter.class,
|
||||
@ -172,22 +197,35 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_12, 0x49 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_12_1, 0x4A ),
|
||||
map( ProtocolConstants.MINECRAFT_1_13, 0x4E ),
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x53 )
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x53 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_15, 0x54 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_16, 0x53 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
EntityStatus.class,
|
||||
map( ProtocolConstants.MINECRAFT_1_8, 0x1A ),
|
||||
map( ProtocolConstants.MINECRAFT_1_9, 0x1B ),
|
||||
map( ProtocolConstants.MINECRAFT_1_13, 0x1C ),
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x1B )
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x1B ),
|
||||
map( ProtocolConstants.MINECRAFT_1_15, 0x1C ),
|
||||
map( ProtocolConstants.MINECRAFT_1_16, 0x1B )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
Commands.class,
|
||||
map( ProtocolConstants.MINECRAFT_1_13, 0x11 )
|
||||
map( ProtocolConstants.MINECRAFT_1_13, 0x11 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_15, 0x12 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_16, 0x11 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
GameState.class,
|
||||
map( ProtocolConstants.MINECRAFT_1_15, 0x1F ),
|
||||
map( ProtocolConstants.MINECRAFT_1_16, 0x1E )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
ViewDistance.class,
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x41 )
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x41 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_15, 0x42 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_16, 0x41 )
|
||||
);
|
||||
|
||||
TO_SERVER.registerPacket(
|
||||
@ -197,7 +235,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_12, 0x0C ),
|
||||
map( ProtocolConstants.MINECRAFT_1_12_1, 0x0B ),
|
||||
map( ProtocolConstants.MINECRAFT_1_13, 0x0E ),
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x0F )
|
||||
map( ProtocolConstants.MINECRAFT_1_14, 0x0F ),
|
||||
map( ProtocolConstants.MINECRAFT_1_16, 0x10 )
|
||||
);
|
||||
TO_SERVER.registerPacket(
|
||||
Chat.class,
|
||||
|
@ -25,6 +25,10 @@ public class ProtocolConstants
|
||||
public static final int MINECRAFT_1_14_2 = 485;
|
||||
public static final int MINECRAFT_1_14_3 = 490;
|
||||
public static final int MINECRAFT_1_14_4 = 498;
|
||||
public static final int MINECRAFT_1_15 = 573;
|
||||
public static final int MINECRAFT_1_15_1 = 575;
|
||||
public static final int MINECRAFT_1_15_2 = 578;
|
||||
public static final int MINECRAFT_1_16 = 735;
|
||||
public static final List<String> SUPPORTED_VERSIONS = Arrays.asList(
|
||||
"1.8.x",
|
||||
"1.9.x",
|
||||
@ -32,7 +36,9 @@ public class ProtocolConstants
|
||||
"1.11.x",
|
||||
"1.12.x",
|
||||
"1.13.x",
|
||||
"1.14.x"
|
||||
"1.14.x",
|
||||
"1.15.x",
|
||||
"1.16.x"
|
||||
);
|
||||
public static final List<Integer> SUPPORTED_VERSION_IDS = Arrays.asList(
|
||||
ProtocolConstants.MINECRAFT_1_8,
|
||||
@ -53,7 +59,11 @@ public class ProtocolConstants
|
||||
ProtocolConstants.MINECRAFT_1_14_1,
|
||||
ProtocolConstants.MINECRAFT_1_14_2,
|
||||
ProtocolConstants.MINECRAFT_1_14_3,
|
||||
ProtocolConstants.MINECRAFT_1_14_4
|
||||
ProtocolConstants.MINECRAFT_1_14_4,
|
||||
ProtocolConstants.MINECRAFT_1_15,
|
||||
ProtocolConstants.MINECRAFT_1_15_1,
|
||||
ProtocolConstants.MINECRAFT_1_15_2,
|
||||
ProtocolConstants.MINECRAFT_1_16
|
||||
);
|
||||
|
||||
public enum Direction
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -16,14 +17,21 @@ import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
public class Chat extends DefinedPacket
|
||||
{
|
||||
|
||||
private static final UUID EMPTY_UUID = new UUID( 0L, 0L );
|
||||
private String message;
|
||||
private byte position;
|
||||
private UUID sender;
|
||||
|
||||
public Chat(String message)
|
||||
{
|
||||
this( message, (byte) 0 );
|
||||
}
|
||||
|
||||
public Chat(String message, byte position)
|
||||
{
|
||||
this( message, position, EMPTY_UUID );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
@ -31,6 +39,10 @@ public class Chat extends DefinedPacket
|
||||
if ( direction == ProtocolConstants.Direction.TO_CLIENT )
|
||||
{
|
||||
position = buf.readByte();
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
|
||||
{
|
||||
sender = readUUID( buf );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,6 +53,10 @@ public class Chat extends DefinedPacket
|
||||
if ( direction == ProtocolConstants.Direction.TO_CLIENT )
|
||||
{
|
||||
buf.writeByte( position );
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
|
||||
{
|
||||
writeUUID( sender, buf );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import com.mojang.brigadier.arguments.DoubleArgumentType;
|
||||
import com.mojang.brigadier.arguments.FloatArgumentType;
|
||||
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||
import com.mojang.brigadier.arguments.LongArgumentType;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.builder.ArgumentBuilder;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
@ -437,6 +438,35 @@ public class Commands extends DefinedPacket
|
||||
}
|
||||
}
|
||||
};
|
||||
private static final ArgumentSerializer<LongArgumentType> LONG = new ArgumentSerializer<LongArgumentType>()
|
||||
{
|
||||
@Override
|
||||
protected LongArgumentType read(ByteBuf buf)
|
||||
{
|
||||
byte flags = buf.readByte();
|
||||
long min = ( flags & 0x1 ) != 0 ? buf.readLong() : Long.MIN_VALUE;
|
||||
long max = ( flags & 0x2 ) != 0 ? buf.readLong() : Long.MAX_VALUE;
|
||||
|
||||
return LongArgumentType.longArg( min, max );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void write(ByteBuf buf, LongArgumentType t)
|
||||
{
|
||||
boolean hasMin = t.getMinimum() != Long.MIN_VALUE;
|
||||
boolean hasMax = t.getMaximum() != Long.MAX_VALUE;
|
||||
|
||||
buf.writeByte( binaryFlag( hasMin, hasMax ) );
|
||||
if ( hasMin )
|
||||
{
|
||||
buf.writeLong( t.getMinimum() );
|
||||
}
|
||||
if ( hasMax )
|
||||
{
|
||||
buf.writeLong( t.getMaximum() );
|
||||
}
|
||||
}
|
||||
};
|
||||
private static final ProperArgumentSerializer<StringArgumentType> STRING = new ProperArgumentSerializer<StringArgumentType>()
|
||||
{
|
||||
@Override
|
||||
@ -475,6 +505,7 @@ public class Commands extends DefinedPacket
|
||||
PROVIDERS.put( "brigadier:float", FLOAT );
|
||||
PROVIDERS.put( "brigadier:double", DOUBLE );
|
||||
PROVIDERS.put( "brigadier:integer", INTEGER );
|
||||
PROVIDERS.put( "brigadier:long", LONG );
|
||||
|
||||
PROVIDERS.put( "brigadier:string", STRING );
|
||||
PROPER_PROVIDERS.put( StringArgumentType.class, STRING );
|
||||
@ -516,6 +547,9 @@ public class Commands extends DefinedPacket
|
||||
PROVIDERS.put( "minecraft:entity_summon", VOID );
|
||||
PROVIDERS.put( "minecraft:dimension", VOID );
|
||||
PROVIDERS.put( "minecraft:time", VOID ); // 1.14
|
||||
PROVIDERS.put( "minecraft:uuid", VOID ); // 1.16
|
||||
PROVIDERS.put( "minecraft:test_argument", VOID ); // 1.16, debug
|
||||
PROVIDERS.put( "minecraft:test_class", VOID ); // 1.16, debug
|
||||
}
|
||||
|
||||
private static ArgumentType<?> read(String key, ByteBuf buf)
|
||||
@ -586,6 +620,7 @@ public class Commands extends DefinedPacket
|
||||
PROVIDERS.put( "minecraft:ask_server", ASK_SERVER );
|
||||
registerDummy( "minecraft:all_recipes" );
|
||||
registerDummy( "minecraft:available_sounds" );
|
||||
registerDummy( "minecraft:available_biomes" );
|
||||
registerDummy( "minecraft:summonable_entities" );
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,42 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.protocol.AbstractPacketHandler;
|
||||
import net.md_5.bungee.protocol.DefinedPacket;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class GameState extends DefinedPacket
|
||||
{
|
||||
|
||||
public static final short IMMEDIATE_RESPAWN = 11;
|
||||
//
|
||||
private short state;
|
||||
private float value;
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
{
|
||||
state = buf.readUnsignedByte();
|
||||
value = buf.readFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
{
|
||||
buf.writeByte( state );
|
||||
buf.writeFloat( value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
}
|
@ -1,6 +1,14 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufInputStream;
|
||||
import io.netty.buffer.ByteBufOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -8,6 +16,8 @@ import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.protocol.AbstractPacketHandler;
|
||||
import net.md_5.bungee.protocol.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
import se.llbit.nbt.NamedTag;
|
||||
import se.llbit.nbt.Tag;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@ -18,31 +28,67 @@ public class Login extends DefinedPacket
|
||||
|
||||
private int entityId;
|
||||
private short gameMode;
|
||||
private int dimension;
|
||||
private short previousGameMode;
|
||||
private Set<String> worldNames;
|
||||
private Tag dimensions;
|
||||
private Object dimension;
|
||||
private String worldName;
|
||||
private long seed;
|
||||
private short difficulty;
|
||||
private short maxPlayers;
|
||||
private String levelType;
|
||||
private int viewDistance;
|
||||
private boolean reducedDebugInfo;
|
||||
private boolean normalRespawn;
|
||||
private boolean debug;
|
||||
private boolean flat;
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
entityId = buf.readInt();
|
||||
gameMode = buf.readUnsignedByte();
|
||||
if ( protocolVersion > ProtocolConstants.MINECRAFT_1_9 )
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
|
||||
{
|
||||
previousGameMode = buf.readUnsignedByte();
|
||||
|
||||
worldNames = new HashSet<>();
|
||||
int worldCount = readVarInt( buf );
|
||||
Preconditions.checkArgument( worldCount < 128, "Too many worlds %s", worldCount );
|
||||
|
||||
for ( int i = 0; i < worldCount; i++ )
|
||||
{
|
||||
worldNames.add( readString( buf ) );
|
||||
}
|
||||
|
||||
dimensions = NamedTag.read( new DataInputStream( new ByteBufInputStream( buf ) ) );
|
||||
Preconditions.checkArgument( !dimensions.isError(), "Error reading dimensions: %s", dimensions.error() );
|
||||
}
|
||||
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
|
||||
{
|
||||
dimension = readString( buf );
|
||||
worldName = readString( buf );
|
||||
} else if ( protocolVersion > ProtocolConstants.MINECRAFT_1_9 )
|
||||
{
|
||||
dimension = buf.readInt();
|
||||
} else
|
||||
{
|
||||
dimension = buf.readByte();
|
||||
dimension = (int) buf.readByte();
|
||||
}
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_15 )
|
||||
{
|
||||
seed = buf.readLong();
|
||||
}
|
||||
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_14 )
|
||||
{
|
||||
difficulty = buf.readUnsignedByte();
|
||||
}
|
||||
maxPlayers = buf.readUnsignedByte();
|
||||
levelType = readString( buf );
|
||||
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_16 )
|
||||
{
|
||||
levelType = readString( buf );
|
||||
}
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_14 )
|
||||
{
|
||||
viewDistance = readVarInt( buf );
|
||||
@ -51,6 +97,15 @@ public class Login extends DefinedPacket
|
||||
{
|
||||
reducedDebugInfo = buf.readBoolean();
|
||||
}
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_15 )
|
||||
{
|
||||
normalRespawn = buf.readBoolean();
|
||||
}
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
|
||||
{
|
||||
debug = buf.readBoolean();
|
||||
flat = buf.readBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -58,19 +113,49 @@ public class Login extends DefinedPacket
|
||||
{
|
||||
buf.writeInt( entityId );
|
||||
buf.writeByte( gameMode );
|
||||
if ( protocolVersion > ProtocolConstants.MINECRAFT_1_9 )
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
|
||||
{
|
||||
buf.writeInt( dimension );
|
||||
buf.writeByte( previousGameMode );
|
||||
|
||||
writeVarInt( worldNames.size(), buf );
|
||||
for ( String world : worldNames )
|
||||
{
|
||||
writeString( world, buf );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
dimensions.write( new DataOutputStream( new ByteBufOutputStream( buf ) ) );
|
||||
} catch ( IOException ex )
|
||||
{
|
||||
throw new RuntimeException( "Exception writing dimensions", ex );
|
||||
}
|
||||
}
|
||||
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
|
||||
{
|
||||
writeString( (String) dimension, buf );
|
||||
writeString( worldName, buf );
|
||||
} else if ( protocolVersion > ProtocolConstants.MINECRAFT_1_9 )
|
||||
{
|
||||
buf.writeInt( (Integer) dimension );
|
||||
} else
|
||||
{
|
||||
buf.writeByte( dimension );
|
||||
buf.writeByte( (Integer) dimension );
|
||||
}
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_15 )
|
||||
{
|
||||
buf.writeLong( seed );
|
||||
}
|
||||
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_14 )
|
||||
{
|
||||
buf.writeByte( difficulty );
|
||||
}
|
||||
buf.writeByte( maxPlayers );
|
||||
writeString( levelType, buf );
|
||||
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_16 )
|
||||
{
|
||||
writeString( levelType, buf );
|
||||
}
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_14 )
|
||||
{
|
||||
writeVarInt( viewDistance, buf );
|
||||
@ -79,6 +164,15 @@ public class Login extends DefinedPacket
|
||||
{
|
||||
buf.writeBoolean( reducedDebugInfo );
|
||||
}
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_15 )
|
||||
{
|
||||
buf.writeBoolean( normalRespawn );
|
||||
}
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
|
||||
{
|
||||
buf.writeBoolean( debug );
|
||||
buf.writeBoolean( flat );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,12 +1,14 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.protocol.AbstractPacketHandler;
|
||||
import net.md_5.bungee.protocol.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@ -15,20 +17,32 @@ import net.md_5.bungee.protocol.DefinedPacket;
|
||||
public class LoginSuccess extends DefinedPacket
|
||||
{
|
||||
|
||||
private String uuid;
|
||||
private UUID uuid;
|
||||
private String username;
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
uuid = readString( buf );
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
|
||||
{
|
||||
uuid = readUUID( buf );
|
||||
} else
|
||||
{
|
||||
uuid = UUID.fromString( readString( buf ) );
|
||||
}
|
||||
username = readString( buf );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
writeString( uuid, buf );
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
|
||||
{
|
||||
writeUUID( uuid, buf );
|
||||
} else
|
||||
{
|
||||
writeString( uuid.toString(), buf );
|
||||
}
|
||||
writeString( username, buf );
|
||||
}
|
||||
|
||||
|
@ -16,33 +16,79 @@ import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
public class Respawn extends DefinedPacket
|
||||
{
|
||||
|
||||
private int dimension;
|
||||
private Object dimension;
|
||||
private String worldName;
|
||||
private long seed;
|
||||
private short difficulty;
|
||||
private short gameMode;
|
||||
private short previousGameMode;
|
||||
private String levelType;
|
||||
private boolean debug;
|
||||
private boolean flat;
|
||||
private boolean copyMeta;
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
dimension = buf.readInt();
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
|
||||
{
|
||||
dimension = readString( buf );
|
||||
worldName = readString( buf );
|
||||
} else
|
||||
{
|
||||
dimension = buf.readInt();
|
||||
}
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_15 )
|
||||
{
|
||||
seed = buf.readLong();
|
||||
}
|
||||
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_14 )
|
||||
{
|
||||
difficulty = buf.readUnsignedByte();
|
||||
}
|
||||
gameMode = buf.readUnsignedByte();
|
||||
levelType = readString( buf );
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
|
||||
{
|
||||
previousGameMode = buf.readUnsignedByte();
|
||||
debug = buf.readBoolean();
|
||||
flat = buf.readBoolean();
|
||||
copyMeta = buf.readBoolean();
|
||||
} else
|
||||
{
|
||||
levelType = readString( buf );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
buf.writeInt( dimension );
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
|
||||
{
|
||||
writeString( (String) dimension, buf );
|
||||
writeString( worldName, buf );
|
||||
} else
|
||||
{
|
||||
buf.writeInt( ( (Integer) dimension ) );
|
||||
}
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_15 )
|
||||
{
|
||||
buf.writeLong( seed );
|
||||
}
|
||||
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_14 )
|
||||
{
|
||||
buf.writeByte( difficulty );
|
||||
}
|
||||
buf.writeByte( gameMode );
|
||||
writeString( levelType, buf );
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
|
||||
{
|
||||
buf.writeByte( previousGameMode );
|
||||
buf.writeBoolean( debug );
|
||||
buf.writeBoolean( flat );
|
||||
buf.writeBoolean( copyMeta );
|
||||
} else
|
||||
{
|
||||
writeString( levelType, buf );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -32,6 +32,8 @@ public class Team extends DefinedPacket
|
||||
|
||||
/**
|
||||
* Packet to destroy a team.
|
||||
*
|
||||
* @param name team name
|
||||
*/
|
||||
public Team(String name)
|
||||
{
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-proxy</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.16-R0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-Proxy</name>
|
||||
@ -20,15 +20,10 @@
|
||||
|
||||
<properties>
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
<maven.javadoc.skip>true</maven.javadoc.skip>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.flowpowered</groupId>
|
||||
<artifactId>flow-nbt</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-codec-haproxy</artifactId>
|
||||
@ -87,13 +82,13 @@
|
||||
<dependency>
|
||||
<groupId>net.sf.jopt-simple</groupId>
|
||||
<artifactId>jopt-simple</artifactId>
|
||||
<version>4.9</version>
|
||||
<version>5.0.4</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.47</version>
|
||||
<version>5.1.48</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
@ -23,6 +23,7 @@ import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@ -39,6 +40,7 @@ import java.util.TimerTask;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.Level;
|
||||
@ -136,6 +138,11 @@ public class BungeeCord extends ProxyServer
|
||||
private final Map<UUID, UserConnection> connectionsByOfflineUUID = new HashMap<>();
|
||||
private final Map<UUID, UserConnection> connectionsByUUID = new HashMap<>();
|
||||
private final ReadWriteLock connectionLock = new ReentrantReadWriteLock();
|
||||
/**
|
||||
* Lock to protect the shutdown process from being triggered simultaneously
|
||||
* from multiple sources.
|
||||
*/
|
||||
private final ReentrantLock shutdownLock = new ReentrantLock();
|
||||
/**
|
||||
* Plugin manager.
|
||||
*/
|
||||
@ -245,7 +252,7 @@ public class BungeeCord extends ProxyServer
|
||||
* Start this proxy instance by loading the configuration, plugins and
|
||||
* starting the connect thread.
|
||||
*
|
||||
* @throws Exception
|
||||
* @throws Exception any critical errors encountered
|
||||
*/
|
||||
@SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE")
|
||||
public void start() throws Exception
|
||||
@ -299,6 +306,15 @@ public class BungeeCord extends ProxyServer
|
||||
}
|
||||
}, 0, TimeUnit.MINUTES.toMillis( 5 ) );
|
||||
metricsThread.scheduleAtFixedRate( new Metrics(), 0, TimeUnit.MINUTES.toMillis( Metrics.PING_INTERVAL ) );
|
||||
|
||||
Runtime.getRuntime().addShutdownHook( new Thread()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
independentThreadStop( getTranslation( "restart" ), false );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
public void startListeners()
|
||||
@ -307,7 +323,7 @@ public class BungeeCord extends ProxyServer
|
||||
{
|
||||
if ( info.isProxyProtocol() )
|
||||
{
|
||||
getLogger().log( Level.WARNING, "Using PROXY protocol for listener {0}, please ensure this listener is adequately firewalled.", info.getHost() );
|
||||
getLogger().log( Level.WARNING, "Using PROXY protocol for listener {0}, please ensure this listener is adequately firewalled.", info.getSocketAddress() );
|
||||
|
||||
if ( connectionThrottle != null )
|
||||
{
|
||||
@ -324,24 +340,26 @@ public class BungeeCord extends ProxyServer
|
||||
if ( future.isSuccess() )
|
||||
{
|
||||
listeners.add( future.channel() );
|
||||
getLogger().log( Level.INFO, "Listening on {0}", info.getHost() );
|
||||
getLogger().log( Level.INFO, "Listening on {0}", info.getSocketAddress() );
|
||||
} else
|
||||
{
|
||||
getLogger().log( Level.WARNING, "Could not bind to host " + info.getHost(), future.cause() );
|
||||
getLogger().log( Level.WARNING, "Could not bind to host " + info.getSocketAddress(), future.cause() );
|
||||
}
|
||||
}
|
||||
};
|
||||
new ServerBootstrap()
|
||||
.channel( PipelineUtils.getServerChannel() )
|
||||
.channel( PipelineUtils.getServerChannel( info.getSocketAddress() ) )
|
||||
.option( ChannelOption.SO_REUSEADDR, true ) // TODO: Move this elsewhere!
|
||||
.childAttr( PipelineUtils.LISTENER, info )
|
||||
.childHandler( PipelineUtils.SERVER_CHILD )
|
||||
.group( eventLoops )
|
||||
.localAddress( info.getHost() )
|
||||
.localAddress( info.getSocketAddress() )
|
||||
.bind().addListener( listener );
|
||||
|
||||
if ( info.isQueryEnabled() )
|
||||
{
|
||||
Preconditions.checkArgument( info.getSocketAddress() instanceof InetSocketAddress, "Can only create query listener on UDP address" );
|
||||
|
||||
ChannelFutureListener bindListener = new ChannelFutureListener()
|
||||
{
|
||||
@Override
|
||||
@ -353,7 +371,7 @@ public class BungeeCord extends ProxyServer
|
||||
getLogger().log( Level.INFO, "Started query on {0}", future.channel().localAddress() );
|
||||
} else
|
||||
{
|
||||
getLogger().log( Level.WARNING, "Could not bind to host " + info.getHost(), future.cause() );
|
||||
getLogger().log( Level.WARNING, "Could not bind to host " + info.getSocketAddress(), future.cause() );
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -385,90 +403,110 @@ public class BungeeCord extends ProxyServer
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void stop(final String reason)
|
||||
public void stop(final String reason)
|
||||
{
|
||||
new Thread( "Shutdown Thread" )
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
independentThreadStop( reason, true );
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
// This must be run on a separate thread to avoid deadlock!
|
||||
@SuppressFBWarnings("DM_EXIT")
|
||||
@SuppressWarnings("TooBroadCatch")
|
||||
private void independentThreadStop(final String reason, boolean callSystemExit)
|
||||
{
|
||||
// Acquire the shutdown lock
|
||||
// This needs to actually block here, otherwise running 'end' and then ctrl+c will cause the thread to terminate prematurely
|
||||
shutdownLock.lock();
|
||||
|
||||
// Acquired the shutdown lock
|
||||
if ( !isRunning )
|
||||
{
|
||||
// Server is already shutting down - nothing to do
|
||||
shutdownLock.unlock();
|
||||
return;
|
||||
}
|
||||
isRunning = false;
|
||||
|
||||
new Thread( "Shutdown Thread" )
|
||||
stopListeners();
|
||||
getLogger().info( "Closing pending connections" );
|
||||
|
||||
connectionLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
@Override
|
||||
@SuppressFBWarnings("DM_EXIT")
|
||||
@SuppressWarnings("TooBroadCatch")
|
||||
public void run()
|
||||
getLogger().log( Level.INFO, "Disconnecting {0} connections", connections.size() );
|
||||
for ( UserConnection user : connections.values() )
|
||||
{
|
||||
stopListeners();
|
||||
getLogger().info( "Closing pending connections" );
|
||||
user.disconnect( reason );
|
||||
}
|
||||
} finally
|
||||
{
|
||||
connectionLock.readLock().unlock();
|
||||
}
|
||||
|
||||
connectionLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
getLogger().log( Level.INFO, "Disconnecting {0} connections", connections.size() );
|
||||
for ( UserConnection user : connections.values() )
|
||||
{
|
||||
user.disconnect( reason );
|
||||
}
|
||||
} finally
|
||||
{
|
||||
connectionLock.readLock().unlock();
|
||||
}
|
||||
try
|
||||
{
|
||||
Thread.sleep( 500 );
|
||||
} catch ( InterruptedException ex )
|
||||
{
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Thread.sleep( 500 );
|
||||
} catch ( InterruptedException ex )
|
||||
{
|
||||
}
|
||||
if ( reconnectHandler != null )
|
||||
{
|
||||
getLogger().info( "Saving reconnect locations" );
|
||||
reconnectHandler.save();
|
||||
reconnectHandler.close();
|
||||
}
|
||||
saveThread.cancel();
|
||||
metricsThread.cancel();
|
||||
|
||||
if ( reconnectHandler != null )
|
||||
{
|
||||
getLogger().info( "Saving reconnect locations" );
|
||||
reconnectHandler.save();
|
||||
reconnectHandler.close();
|
||||
}
|
||||
saveThread.cancel();
|
||||
metricsThread.cancel();
|
||||
|
||||
// TODO: Fix this shit
|
||||
getLogger().info( "Disabling plugins" );
|
||||
for ( Plugin plugin : Lists.reverse( new ArrayList<>( pluginManager.getPlugins() ) ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
plugin.onDisable();
|
||||
for ( Handler handler : plugin.getLogger().getHandlers() )
|
||||
{
|
||||
handler.close();
|
||||
}
|
||||
} catch ( Throwable t )
|
||||
{
|
||||
getLogger().log( Level.SEVERE, "Exception disabling plugin " + plugin.getDescription().getName(), t );
|
||||
}
|
||||
getScheduler().cancel( plugin );
|
||||
plugin.getExecutorService().shutdownNow();
|
||||
}
|
||||
|
||||
getLogger().info( "Closing IO threads" );
|
||||
eventLoops.shutdownGracefully();
|
||||
try
|
||||
{
|
||||
eventLoops.awaitTermination( Long.MAX_VALUE, TimeUnit.NANOSECONDS );
|
||||
} catch ( InterruptedException ex )
|
||||
{
|
||||
}
|
||||
|
||||
getLogger().info( "Thank you and goodbye" );
|
||||
// Need to close loggers after last message!
|
||||
for ( Handler handler : getLogger().getHandlers() )
|
||||
getLogger().info( "Disabling plugins" );
|
||||
for ( Plugin plugin : Lists.reverse( new ArrayList<>( pluginManager.getPlugins() ) ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
plugin.onDisable();
|
||||
for ( Handler handler : plugin.getLogger().getHandlers() )
|
||||
{
|
||||
handler.close();
|
||||
}
|
||||
System.exit( 0 );
|
||||
} catch ( Throwable t )
|
||||
{
|
||||
getLogger().log( Level.SEVERE, "Exception disabling plugin " + plugin.getDescription().getName(), t );
|
||||
}
|
||||
}.start();
|
||||
getScheduler().cancel( plugin );
|
||||
plugin.getExecutorService().shutdownNow();
|
||||
}
|
||||
|
||||
getLogger().info( "Closing IO threads" );
|
||||
eventLoops.shutdownGracefully();
|
||||
try
|
||||
{
|
||||
eventLoops.awaitTermination( Long.MAX_VALUE, TimeUnit.NANOSECONDS );
|
||||
} catch ( InterruptedException ex )
|
||||
{
|
||||
}
|
||||
|
||||
getLogger().info( "Thank you and goodbye" );
|
||||
// Need to close loggers after last message!
|
||||
for ( Handler handler : getLogger().getHandlers() )
|
||||
{
|
||||
handler.close();
|
||||
}
|
||||
|
||||
// Unlock the thread before optionally calling system exit, which might invoke this function again.
|
||||
// If that happens, the system will obtain the lock, and then see that isRunning == false and return without doing anything.
|
||||
shutdownLock.unlock();
|
||||
|
||||
if ( callSystemExit )
|
||||
{
|
||||
System.exit( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -646,6 +684,12 @@ public class BungeeCord extends ProxyServer
|
||||
|
||||
@Override
|
||||
public ServerInfo constructServerInfo(String name, InetSocketAddress address, String motd, boolean restricted)
|
||||
{
|
||||
return constructServerInfo( name, (SocketAddress) address, motd, restricted );
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerInfo constructServerInfo(String name, SocketAddress address, String motd, boolean restricted)
|
||||
{
|
||||
return new BungeeServerInfo( name, address, motd, restricted );
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@ -30,18 +31,20 @@ import net.md_5.bungee.netty.PipelineUtils;
|
||||
import net.md_5.bungee.protocol.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.packet.PluginMessage;
|
||||
|
||||
// CHECKSTYLE:OFF
|
||||
@RequiredArgsConstructor
|
||||
@ToString(of =
|
||||
{
|
||||
"name", "address", "restricted"
|
||||
"name", "socketAddress", "restricted"
|
||||
})
|
||||
// CHECKSTYLE:ON
|
||||
public class BungeeServerInfo implements ServerInfo
|
||||
{
|
||||
|
||||
@Getter
|
||||
private final String name;
|
||||
@Getter
|
||||
private final InetSocketAddress address;
|
||||
private final SocketAddress socketAddress;
|
||||
private final Collection<ProxiedPlayer> players = new ArrayList<>();
|
||||
@Getter
|
||||
private final String motd;
|
||||
@ -91,7 +94,7 @@ public class BungeeServerInfo implements ServerInfo
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return address.hashCode();
|
||||
return socketAddress.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -122,6 +125,24 @@ public class BungeeServerInfo implements ServerInfo
|
||||
}
|
||||
}
|
||||
|
||||
private long lastPing;
|
||||
private ServerPing cachedPing;
|
||||
|
||||
public void cachePing(ServerPing serverPing)
|
||||
{
|
||||
if ( ProxyServer.getInstance().getConfig().getRemotePingCache() > 0 )
|
||||
{
|
||||
this.cachedPing = serverPing;
|
||||
this.lastPing = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getAddress()
|
||||
{
|
||||
return (InetSocketAddress) socketAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ping(final Callback<ServerPing> callback)
|
||||
{
|
||||
@ -132,6 +153,18 @@ public class BungeeServerInfo implements ServerInfo
|
||||
{
|
||||
Preconditions.checkNotNull( callback, "callback" );
|
||||
|
||||
int pingCache = ProxyServer.getInstance().getConfig().getRemotePingCache();
|
||||
if ( pingCache > 0 && cachedPing != null && ( lastPing - System.currentTimeMillis() ) > pingCache )
|
||||
{
|
||||
cachedPing = null;
|
||||
}
|
||||
|
||||
if ( cachedPing != null )
|
||||
{
|
||||
callback.done( cachedPing, null );
|
||||
return;
|
||||
}
|
||||
|
||||
ChannelFutureListener listener = new ChannelFutureListener()
|
||||
{
|
||||
@Override
|
||||
@ -147,11 +180,11 @@ public class BungeeServerInfo implements ServerInfo
|
||||
}
|
||||
};
|
||||
new Bootstrap()
|
||||
.channel( PipelineUtils.getChannel() )
|
||||
.channel( PipelineUtils.getChannel( socketAddress ) )
|
||||
.group( BungeeCord.getInstance().eventLoops )
|
||||
.handler( PipelineUtils.BASE )
|
||||
.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000 ) // TODO: Configurable
|
||||
.remoteAddress( getAddress() )
|
||||
.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, BungeeCord.getInstance().getConfig().getRemotePingTimeout() )
|
||||
.remoteAddress( socketAddress )
|
||||
.connect()
|
||||
.addListener( listener );
|
||||
}
|
||||
|
@ -6,48 +6,65 @@ import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class ConnectionThrottle
|
||||
{
|
||||
|
||||
private final LoadingCache<InetAddress, Integer> throttle;
|
||||
private final LoadingCache<InetAddress, AtomicInteger> throttle;
|
||||
private final int throttleLimit;
|
||||
|
||||
public ConnectionThrottle(int throttleTime, int throttleLimit)
|
||||
{
|
||||
this(Ticker.systemTicker(), throttleTime, throttleLimit);
|
||||
this( Ticker.systemTicker(), throttleTime, throttleLimit );
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
ConnectionThrottle(Ticker ticker, int throttleTime, int throttleLimit)
|
||||
{
|
||||
this.throttle = CacheBuilder.newBuilder()
|
||||
.ticker(ticker)
|
||||
.ticker( ticker )
|
||||
.concurrencyLevel( Runtime.getRuntime().availableProcessors() )
|
||||
.initialCapacity( 100 )
|
||||
.expireAfterWrite( throttleTime, TimeUnit.MILLISECONDS )
|
||||
.build( new CacheLoader<InetAddress, Integer>()
|
||||
.build( new CacheLoader<InetAddress, AtomicInteger>()
|
||||
{
|
||||
@Override
|
||||
public Integer load(InetAddress key) throws Exception
|
||||
public AtomicInteger load(InetAddress key) throws Exception
|
||||
{
|
||||
return 0;
|
||||
return new AtomicInteger();
|
||||
}
|
||||
} );
|
||||
this.throttleLimit = throttleLimit;
|
||||
}
|
||||
|
||||
public void unthrottle(InetAddress address)
|
||||
public void unthrottle(SocketAddress socketAddress)
|
||||
{
|
||||
int throttleCount = throttle.getUnchecked( address ) - 1;
|
||||
throttle.put( address, throttleCount );
|
||||
if ( !( socketAddress instanceof InetSocketAddress ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
InetAddress address = ( (InetSocketAddress) socketAddress ).getAddress();
|
||||
AtomicInteger throttleCount = throttle.getIfPresent( address );
|
||||
if ( throttleCount != null )
|
||||
{
|
||||
throttleCount.decrementAndGet();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean throttle(InetAddress address)
|
||||
public boolean throttle(SocketAddress socketAddress)
|
||||
{
|
||||
int throttleCount = throttle.getUnchecked( address ) + 1;
|
||||
throttle.put( address, throttleCount );
|
||||
if ( !( socketAddress instanceof InetSocketAddress ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
InetAddress address = ( (InetSocketAddress) socketAddress ).getAddress();
|
||||
int throttleCount = throttle.getUnchecked( address ).incrementAndGet();
|
||||
|
||||
return throttleCount > throttleLimit;
|
||||
}
|
||||
|
@ -52,7 +52,10 @@ public class Metrics extends TimerTask
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic method that posts a plugin to the metrics website
|
||||
* Generic method that posts a plugin to the metrics website.
|
||||
*
|
||||
* @param isPing first post or not
|
||||
* @throws IOException any errors encountered
|
||||
*/
|
||||
private void postPlugin(boolean isPing) throws IOException
|
||||
{
|
||||
@ -110,6 +113,7 @@ public class Metrics extends TimerTask
|
||||
* @param buffer the StringBuilder to append the data pair onto
|
||||
* @param key the key value
|
||||
* @param value the value
|
||||
* @throws UnsupportedEncodingException if UTF-8 encoding not supported
|
||||
*/
|
||||
private static void encodeDataPair(final StringBuilder buffer, final String key, final String value) throws UnsupportedEncodingException
|
||||
{
|
||||
@ -121,6 +125,7 @@ public class Metrics extends TimerTask
|
||||
*
|
||||
* @param text the text to encode
|
||||
* @return the encoded text, as UTF-8
|
||||
* @throws UnsupportedEncodingException if UTF-8 encoding not supported
|
||||
*/
|
||||
private static String encode(final String text) throws UnsupportedEncodingException
|
||||
{
|
||||
|
@ -1,17 +0,0 @@
|
||||
package net.md_5.bungee;
|
||||
|
||||
import net.md_5.bungee.protocol.packet.ClientStatus;
|
||||
import net.md_5.bungee.protocol.packet.PluginMessage;
|
||||
import net.md_5.bungee.protocol.packet.Respawn;
|
||||
|
||||
public class PacketConstants
|
||||
{
|
||||
|
||||
public static final Respawn DIM1_SWITCH = new Respawn( (byte) 1, (byte) 0, (byte) 0, "default" );
|
||||
public static final Respawn DIM2_SWITCH = new Respawn( (byte) -1, (byte) 0, (byte) 0, "default" );
|
||||
public static final ClientStatus CLIENT_LOGIN = new ClientStatus( (byte) 0 );
|
||||
public static final PluginMessage FORGE_MOD_REQUEST = new PluginMessage( "FML", new byte[]
|
||||
{
|
||||
0, 0, 0, 0, 0, 2
|
||||
}, false );
|
||||
}
|
@ -2,6 +2,10 @@ package net.md_5.bungee;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Queue;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
@ -25,8 +29,7 @@ public class ServerConnection implements Server
|
||||
@Getter
|
||||
private final boolean forgeServer = false;
|
||||
@Getter
|
||||
@Setter
|
||||
private long sentPingId = -1;
|
||||
private final Queue<KeepAliveData> keepAlives = new ArrayDeque<>();
|
||||
|
||||
private final Unsafe unsafe = new Unsafe()
|
||||
{
|
||||
@ -54,7 +57,7 @@ public class ServerConnection implements Server
|
||||
{
|
||||
Preconditions.checkArgument( reason.length == 0, "Server cannot have disconnect reason" );
|
||||
|
||||
ch.delayedClose( null );
|
||||
ch.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -65,6 +68,12 @@ public class ServerConnection implements Server
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getAddress()
|
||||
{
|
||||
return (InetSocketAddress) getSocketAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getSocketAddress()
|
||||
{
|
||||
return getInfo().getAddress();
|
||||
}
|
||||
@ -80,4 +89,12 @@ public class ServerConnection implements Server
|
||||
{
|
||||
return unsafe;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class KeepAliveData
|
||||
{
|
||||
|
||||
private final long id;
|
||||
private final long time;
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package net.md_5.bungee;
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Locale;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
@ -36,6 +37,7 @@ import net.md_5.bungee.protocol.Protocol;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
import net.md_5.bungee.protocol.packet.EncryptionRequest;
|
||||
import net.md_5.bungee.protocol.packet.EntityStatus;
|
||||
import net.md_5.bungee.protocol.packet.GameState;
|
||||
import net.md_5.bungee.protocol.packet.Handshake;
|
||||
import net.md_5.bungee.protocol.packet.Kick;
|
||||
import net.md_5.bungee.protocol.packet.Login;
|
||||
@ -96,7 +98,7 @@ public class ServerConnector extends PacketHandler
|
||||
Handshake originalHandshake = user.getPendingConnection().getHandshake();
|
||||
Handshake copiedHandshake = new Handshake( originalHandshake.getProtocolVersion(), originalHandshake.getHost(), originalHandshake.getPort(), 2 );
|
||||
|
||||
if ( BungeeCord.getInstance().config.isIpForward() )
|
||||
if ( BungeeCord.getInstance().config.isIpForward() && user.getSocketAddress() instanceof InetSocketAddress )
|
||||
{
|
||||
String newHost = copiedHandshake.getHost() + "\00" + user.getAddress().getHostString() + "\00" + user.getUUID();
|
||||
|
||||
@ -210,8 +212,8 @@ public class ServerConnector extends PacketHandler
|
||||
user.setServerEntityId( login.getEntityId() );
|
||||
|
||||
// Set tab list size, TODO: what shall we do about packet mutability
|
||||
Login modLogin = new Login( login.getEntityId(), login.getGameMode(), (byte) login.getDimension(), login.getDifficulty(),
|
||||
(byte) user.getPendingConnection().getListener().getTabListSize(), login.getLevelType(), login.getViewDistance(), login.isReducedDebugInfo() );
|
||||
Login modLogin = new Login( login.getEntityId(), login.getGameMode(), login.getPreviousGameMode(), login.getWorldNames(), login.getDimensions(), login.getDimension(), login.getWorldName(), login.getSeed(), login.getDifficulty(),
|
||||
(byte) user.getPendingConnection().getListener().getTabListSize(), login.getLevelType(), login.getViewDistance(), login.isReducedDebugInfo(), login.isNormalRespawn(), login.isDebug(), login.isFlat() );
|
||||
|
||||
user.unsafe().sendPacket( modLogin );
|
||||
|
||||
@ -250,15 +252,30 @@ public class ServerConnector extends PacketHandler
|
||||
|
||||
// Update debug info from login packet
|
||||
user.unsafe().sendPacket( new EntityStatus( user.getClientEntityId(), login.isReducedDebugInfo() ? EntityStatus.DEBUG_INFO_REDUCED : EntityStatus.DEBUG_INFO_NORMAL ) );
|
||||
// And immediate respawn
|
||||
if ( user.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_15 )
|
||||
{
|
||||
user.unsafe().sendPacket( new GameState( GameState.IMMEDIATE_RESPAWN, login.isNormalRespawn() ? 0 : 1 ) );
|
||||
}
|
||||
|
||||
user.setDimensionChange( true );
|
||||
if ( login.getDimension() == user.getDimension() )
|
||||
if ( login.getDimension().equals( user.getDimension() ) )
|
||||
{
|
||||
user.unsafe().sendPacket( new Respawn( ( login.getDimension() >= 0 ? -1 : 0 ), login.getDifficulty(), login.getGameMode(), login.getLevelType() ) );
|
||||
Object newDim;
|
||||
String worldName = login.getWorldName();
|
||||
if ( login.getDimension() instanceof Integer )
|
||||
{
|
||||
newDim = ( (Integer) login.getDimension() >= 0 ? -1 : 0 );
|
||||
} else
|
||||
{
|
||||
newDim = worldName = ( "minecraft:overworld".equals( (String) login.getDimension() ) ) ? "minecraft:the_nether" : "minecraft:overworld";
|
||||
}
|
||||
|
||||
user.unsafe().sendPacket( new Respawn( newDim, worldName, login.getSeed(), login.getDifficulty(), login.getGameMode(), login.getPreviousGameMode(), login.getLevelType(), login.isDebug(), login.isFlat(), false ) );
|
||||
}
|
||||
|
||||
user.setServerEntityId( login.getEntityId() );
|
||||
user.unsafe().sendPacket( new Respawn( login.getDimension(), login.getDifficulty(), login.getGameMode(), login.getLevelType() ) );
|
||||
user.unsafe().sendPacket( new Respawn( login.getDimension(), login.getWorldName(), login.getSeed(), login.getDifficulty(), login.getGameMode(), login.getPreviousGameMode(), login.getLevelType(), login.isDebug(), login.isFlat(), false ) );
|
||||
if ( user.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_14 )
|
||||
{
|
||||
user.unsafe().sendPacket( new ViewDistance( login.getViewDistance() ) );
|
||||
|
@ -10,6 +10,7 @@ import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
@ -51,6 +52,7 @@ import net.md_5.bungee.protocol.MinecraftDecoder;
|
||||
import net.md_5.bungee.protocol.MinecraftEncoder;
|
||||
import net.md_5.bungee.protocol.PacketWrapper;
|
||||
import net.md_5.bungee.protocol.Protocol;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
import net.md_5.bungee.protocol.packet.Chat;
|
||||
import net.md_5.bungee.protocol.packet.ClientSettings;
|
||||
import net.md_5.bungee.protocol.packet.Kick;
|
||||
@ -82,7 +84,7 @@ public final class UserConnection implements ProxiedPlayer
|
||||
private ServerConnection server;
|
||||
@Getter
|
||||
@Setter
|
||||
private int dimension;
|
||||
private Object dimension;
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean dimensionChange = true;
|
||||
@ -91,9 +93,6 @@ public final class UserConnection implements ProxiedPlayer
|
||||
/*========================================================================*/
|
||||
@Getter
|
||||
@Setter
|
||||
private long sentPingTime;
|
||||
@Getter
|
||||
@Setter
|
||||
private int ping = 100;
|
||||
@Getter
|
||||
@Setter
|
||||
@ -275,7 +274,7 @@ public final class UserConnection implements ProxiedPlayer
|
||||
Preconditions.checkNotNull( request, "request" );
|
||||
|
||||
final Callback<ServerConnectRequest.Result> callback = request.getCallback();
|
||||
ServerConnectEvent event = new ServerConnectEvent( this, request.getTarget(), request.getReason() );
|
||||
ServerConnectEvent event = new ServerConnectEvent( this, request.getTarget(), request.getReason(), request );
|
||||
if ( bungee.getPluginManager().callEvent( event ).isCancelled() )
|
||||
{
|
||||
if ( callback != null )
|
||||
@ -358,13 +357,13 @@ public final class UserConnection implements ProxiedPlayer
|
||||
}
|
||||
};
|
||||
Bootstrap b = new Bootstrap()
|
||||
.channel( PipelineUtils.getChannel() )
|
||||
.channel( PipelineUtils.getChannel( target.getAddress() ) )
|
||||
.group( ch.getHandle().eventLoop() )
|
||||
.handler( initializer )
|
||||
.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, request.getConnectTimeout() )
|
||||
.remoteAddress( target.getAddress() );
|
||||
// Windows is bugged, multi homed users will just have to live with random connecting IPs
|
||||
if ( getPendingConnection().getListener().isSetLocalAddress() && !PlatformDependent.isWindows() )
|
||||
if ( getPendingConnection().getListener().isSetLocalAddress() && !PlatformDependent.isWindows() && getPendingConnection().getListener().getSocketAddress() instanceof InetSocketAddress )
|
||||
{
|
||||
b.localAddress( getPendingConnection().getListener().getHost().getHostString(), 0 );
|
||||
}
|
||||
@ -398,7 +397,7 @@ public final class UserConnection implements ProxiedPlayer
|
||||
getName(), BaseComponent.toLegacyText( reason )
|
||||
} );
|
||||
|
||||
ch.delayedClose( new Kick( ComponentSerializer.toString( reason ) ) );
|
||||
ch.close( new Kick( ComponentSerializer.toString( reason ) ) );
|
||||
|
||||
if ( server != null )
|
||||
{
|
||||
@ -453,10 +452,20 @@ public final class UserConnection implements ProxiedPlayer
|
||||
// transform score components
|
||||
message = ChatComponentTransformer.getInstance().transform( this, message );
|
||||
|
||||
// Action bar doesn't display the new JSON formattings, legacy works - send it using this for now
|
||||
if ( position == ChatMessageType.ACTION_BAR )
|
||||
{
|
||||
sendMessage( position, ComponentSerializer.toString( new TextComponent( BaseComponent.toLegacyText( message ) ) ) );
|
||||
// Versions older than 1.11 cannot send the Action bar with the new JSON formattings
|
||||
// Fix by converting to a legacy message, see https://bugs.mojang.com/browse/MC-119145
|
||||
if ( getPendingConnection().getVersion() <= ProtocolConstants.MINECRAFT_1_10 )
|
||||
{
|
||||
sendMessage( position, ComponentSerializer.toString( new TextComponent( BaseComponent.toLegacyText( message ) ) ) );
|
||||
} else
|
||||
{
|
||||
net.md_5.bungee.protocol.packet.Title title = new net.md_5.bungee.protocol.packet.Title();
|
||||
title.setAction( net.md_5.bungee.protocol.packet.Title.Action.ACTIONBAR );
|
||||
title.setText( ComponentSerializer.toString( message ) );
|
||||
unsafe.sendPacket( title );
|
||||
}
|
||||
} else
|
||||
{
|
||||
sendMessage( position, ComponentSerializer.toString( message ) );
|
||||
@ -486,6 +495,12 @@ public final class UserConnection implements ProxiedPlayer
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getAddress()
|
||||
{
|
||||
return (InetSocketAddress) getSocketAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getSocketAddress()
|
||||
{
|
||||
return ch.getRemoteAddress();
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.md_5.bungee.command;
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
@ -18,16 +17,16 @@ public class CommandIP extends PlayerCommand
|
||||
{
|
||||
if ( args.length < 1 )
|
||||
{
|
||||
sender.sendMessage( ChatColor.RED + "Please follow this command by a user name" );
|
||||
sender.sendMessage( ProxyServer.getInstance().getTranslation( "username_needed" ) );
|
||||
return;
|
||||
}
|
||||
ProxiedPlayer user = ProxyServer.getInstance().getPlayer( args[0] );
|
||||
if ( user == null )
|
||||
{
|
||||
sender.sendMessage( ChatColor.RED + "That user is not online" );
|
||||
sender.sendMessage( ProxyServer.getInstance().getTranslation( "user_not_online" ) );
|
||||
} else
|
||||
{
|
||||
sender.sendMessage( ChatColor.BLUE + "IP of " + args[0] + " is " + user.getAddress() );
|
||||
sender.sendMessage( ProxyServer.getInstance().getTranslation( "command_ip", args[0], user.getSocketAddress() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package net.md_5.bungee.command;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import net.md_5.bungee.Util;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
@ -24,11 +23,11 @@ public class CommandPerms extends Command
|
||||
{
|
||||
permissions.addAll( ProxyServer.getInstance().getConfigurationAdapter().getPermissions( group ) );
|
||||
}
|
||||
sender.sendMessage( ChatColor.GOLD + "You have the following groups: " + Util.csv( sender.getGroups() ) );
|
||||
sender.sendMessage( ProxyServer.getInstance().getTranslation( "command_perms_groups", Util.csv( sender.getGroups() ) ) );
|
||||
|
||||
for ( String permission : permissions )
|
||||
{
|
||||
sender.sendMessage( ChatColor.BLUE + "- " + permission );
|
||||
sender.sendMessage( ProxyServer.getInstance().getTranslation( "command_perms_permission", permission ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,8 +52,11 @@ public class Configuration implements ProxyConfig
|
||||
*/
|
||||
private boolean logCommands;
|
||||
private boolean logPings = true;
|
||||
private int remotePingCache = -1;
|
||||
private int playerLimit = -1;
|
||||
private Collection<String> disabledCommands;
|
||||
private int serverConnectTimeout = 5000;
|
||||
private int remotePingTimeout = 5000;
|
||||
private int throttle = 4000;
|
||||
private int throttleLimit = 3;
|
||||
private boolean ipForward;
|
||||
@ -85,7 +88,10 @@ public class Configuration implements ProxyConfig
|
||||
onlineMode = adapter.getBoolean( "online_mode", onlineMode );
|
||||
logCommands = adapter.getBoolean( "log_commands", logCommands );
|
||||
logPings = adapter.getBoolean( "log_pings", logPings );
|
||||
remotePingCache = adapter.getInt( "remote_ping_cache", remotePingCache );
|
||||
playerLimit = adapter.getInt( "player_limit", playerLimit );
|
||||
serverConnectTimeout = adapter.getInt( "server_connect_timeout", serverConnectTimeout );
|
||||
remotePingTimeout = adapter.getInt( "remote_ping_timeout", remotePingTimeout );
|
||||
throttle = adapter.getInt( "connection_throttle", throttle );
|
||||
throttleLimit = adapter.getInt( "connection_throttle_limit", throttleLimit );
|
||||
ipForward = adapter.getBoolean( "ip_forward", ipForward );
|
||||
|
@ -1,12 +1,15 @@
|
||||
package net.md_5.bungee.conf;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@ -173,7 +176,7 @@ public class YamlConfig implements ConfigurationAdapter
|
||||
{
|
||||
try
|
||||
{
|
||||
try ( FileWriter wr = new FileWriter( file ) )
|
||||
try ( Writer wr = new OutputStreamWriter( new FileOutputStream( file ), Charsets.UTF_8 ) )
|
||||
{
|
||||
yaml.dump( config, wr );
|
||||
}
|
||||
@ -215,7 +218,7 @@ public class YamlConfig implements ConfigurationAdapter
|
||||
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 );
|
||||
InetSocketAddress address = Util.getAddr( addr );
|
||||
SocketAddress address = Util.getAddr( addr );
|
||||
ServerInfo info = ProxyServer.getInstance().constructServerInfo( name, address, motd, restricted );
|
||||
ret.put( name, info );
|
||||
}
|
||||
@ -246,7 +249,7 @@ public class YamlConfig implements ConfigurationAdapter
|
||||
boolean forceDefault = get( "force_default_server", false, val );
|
||||
String host = get( "host", "0.0.0.0:25577", val );
|
||||
int tabListSize = get( "tab_size", 60, val );
|
||||
InetSocketAddress address = Util.getAddr( host );
|
||||
SocketAddress address = Util.getAddr( host );
|
||||
Map<String, String> forced = new CaseInsensitiveMap<>( get( "forced_hosts", forcedDef, val ) );
|
||||
String tabListName = get( "tab_list", "GLOBAL_PING", val );
|
||||
DefaultTabList value = DefaultTabList.valueOf( tabListName.toUpperCase( Locale.ROOT ) );
|
||||
|
@ -15,12 +15,15 @@ import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.unix.DomainSocketAddress;
|
||||
import java.io.DataInput;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.md_5.bungee.ServerConnection;
|
||||
import net.md_5.bungee.ServerConnection.KeepAliveData;
|
||||
import net.md_5.bungee.UserConnection;
|
||||
import net.md_5.bungee.Util;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
@ -122,8 +125,11 @@ public class DownstreamBridge extends PacketHandler
|
||||
@Override
|
||||
public void handle(KeepAlive alive) throws Exception
|
||||
{
|
||||
server.setSentPingId( alive.getRandomId() );
|
||||
con.setSentPingTime( System.currentTimeMillis() );
|
||||
int timeout = bungee.getConfig().getTimeout();
|
||||
if ( timeout <= 0 || server.getKeepAlives().size() < timeout / 50 ) // Some people disable timeout, otherwise allow a theoretical maximum of 1 keepalive per tick
|
||||
{
|
||||
server.getKeepAlives().add( new KeepAliveData( alive.getRandomId(), System.currentTimeMillis() ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -359,8 +365,15 @@ public class DownstreamBridge extends PacketHandler
|
||||
if ( subChannel.equals( "IP" ) )
|
||||
{
|
||||
out.writeUTF( "IP" );
|
||||
out.writeUTF( con.getAddress().getHostString() );
|
||||
out.writeInt( con.getAddress().getPort() );
|
||||
if ( con.getSocketAddress() instanceof InetSocketAddress )
|
||||
{
|
||||
out.writeUTF( con.getAddress().getHostString() );
|
||||
out.writeInt( con.getAddress().getPort() );
|
||||
} else
|
||||
{
|
||||
out.writeUTF( "unix://" + ( (DomainSocketAddress) con.getSocketAddress() ).path() );
|
||||
out.writeInt( 0 );
|
||||
}
|
||||
}
|
||||
if ( subChannel.equals( "PlayerCount" ) )
|
||||
{
|
||||
|
@ -5,6 +5,7 @@ import com.google.common.base.Preconditions;
|
||||
import com.google.gson.Gson;
|
||||
import java.math.BigInteger;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.URLEncoder;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.List;
|
||||
@ -117,6 +118,11 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
HANDSHAKE, STATUS, PING, USERNAME, ENCRYPT, FINISHED;
|
||||
}
|
||||
|
||||
private boolean canSendKickMessage()
|
||||
{
|
||||
return thisState == State.USERNAME || thisState == State.ENCRYPT || thisState == State.FINISHED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connected(ChannelWrapper channel) throws Exception
|
||||
{
|
||||
@ -126,7 +132,13 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
@Override
|
||||
public void exception(Throwable t) throws Exception
|
||||
{
|
||||
disconnect( ChatColor.RED + Util.exception( t ) );
|
||||
if ( canSendKickMessage() )
|
||||
{
|
||||
disconnect( ChatColor.RED + Util.exception( t ) );
|
||||
} else
|
||||
{
|
||||
ch.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -207,6 +219,15 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
return pos == -1 ? str : str.substring( 0, pos );
|
||||
}
|
||||
|
||||
private ServerPing getPingInfo(String motd, int protocol)
|
||||
{
|
||||
return new ServerPing(
|
||||
new ServerPing.Protocol( bungee.getName() + " " + bungee.getGameVersion(), protocol ),
|
||||
new ServerPing.Players( listener.getMaxPlayers(), bungee.getOnlineCount(), null ),
|
||||
motd, BungeeCord.getInstance().config.getFaviconObject()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(StatusRequest statusRequest) throws Exception
|
||||
{
|
||||
@ -214,6 +235,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
|
||||
ServerInfo forced = AbstractReconnectHandler.getForcedHost( this );
|
||||
final String motd = ( forced != null ) ? forced.getMotd() : listener.getMotd();
|
||||
final int protocol = ( ProtocolConstants.SUPPORTED_VERSION_IDS.contains( handshake.getProtocolVersion() ) ) ? handshake.getProtocolVersion() : bungee.getProtocolVersion();
|
||||
|
||||
Callback<ServerPing> pingBack = new Callback<ServerPing>()
|
||||
{
|
||||
@ -222,8 +244,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
{
|
||||
if ( error != null )
|
||||
{
|
||||
result = new ServerPing();
|
||||
result.setDescription( bungee.getTranslation( "ping_cannot_connect" ) );
|
||||
result = getPingInfo( bungee.getTranslation( "ping_cannot_connect" ), protocol );
|
||||
bungee.getLogger().log( Level.WARNING, "Error pinging remote server", error );
|
||||
}
|
||||
|
||||
@ -236,7 +257,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
unsafe.sendPacket( new StatusResponse( gson.toJson( pingResult.getResponse() ) ) );
|
||||
if ( bungee.getConnectionThrottle() != null )
|
||||
{
|
||||
bungee.getConnectionThrottle().unthrottle( getAddress().getAddress() );
|
||||
bungee.getConnectionThrottle().unthrottle( getSocketAddress() );
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -250,12 +271,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
( (BungeeServerInfo) forced ).ping( pingBack, handshake.getProtocolVersion() );
|
||||
} else
|
||||
{
|
||||
int protocol = ( ProtocolConstants.SUPPORTED_VERSION_IDS.contains( handshake.getProtocolVersion() ) ) ? handshake.getProtocolVersion() : bungee.getProtocolVersion();
|
||||
pingBack.done( new ServerPing(
|
||||
new ServerPing.Protocol( bungee.getName() + " " + bungee.getGameVersion(), protocol ),
|
||||
new ServerPing.Players( listener.getMaxPlayers(), bungee.getOnlineCount(), null ),
|
||||
motd, BungeeCord.getInstance().config.getFaviconObject() ),
|
||||
null );
|
||||
pingBack.done( getPingInfo( motd, protocol ), null );
|
||||
}
|
||||
|
||||
thisState = State.PING;
|
||||
@ -295,10 +311,6 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
}
|
||||
|
||||
this.virtualHost = InetSocketAddress.createUnresolved( handshake.getHost(), handshake.getPort() );
|
||||
if ( bungee.getConfig().isLogPings() )
|
||||
{
|
||||
bungee.getLogger().log( Level.INFO, "{0} has connected", this );
|
||||
}
|
||||
|
||||
bungee.getPluginManager().callEvent( new PlayerHandshakeEvent( InitialHandler.this, handshake ) );
|
||||
|
||||
@ -306,15 +318,16 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
{
|
||||
case 1:
|
||||
// Ping
|
||||
if ( bungee.getConfig().isLogPings() )
|
||||
{
|
||||
bungee.getLogger().log( Level.INFO, "{0} has pinged", this );
|
||||
}
|
||||
thisState = State.STATUS;
|
||||
ch.setProtocol( Protocol.STATUS );
|
||||
break;
|
||||
case 2:
|
||||
// Login
|
||||
if ( !bungee.getConfig().isLogPings() )
|
||||
{
|
||||
bungee.getLogger().log( Level.INFO, "{0} has connected", this );
|
||||
}
|
||||
bungee.getLogger().log( Level.INFO, "{0} has connected", this );
|
||||
thisState = State.USERNAME;
|
||||
ch.setProtocol( Protocol.LOGIN );
|
||||
|
||||
@ -331,7 +344,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException( "Cannot request protocol " + handshake.getRequestedProtocol() );
|
||||
throw new QuietException( "Cannot request protocol " + handshake.getRequestedProtocol() );
|
||||
}
|
||||
}
|
||||
|
||||
@ -421,7 +434,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
}
|
||||
String encodedHash = URLEncoder.encode( new BigInteger( sha.digest() ).toString( 16 ), "UTF-8" );
|
||||
|
||||
String preventProxy = ( ( BungeeCord.getInstance().config.isPreventProxyConnections() ) ? "&ip=" + URLEncoder.encode( getAddress().getAddress().getHostAddress(), "UTF-8" ) : "" );
|
||||
String preventProxy = ( BungeeCord.getInstance().config.isPreventProxyConnections() && getSocketAddress() instanceof InetSocketAddress ) ? "&ip=" + URLEncoder.encode( getAddress().getAddress().getHostAddress(), "UTF-8" ) : "";
|
||||
String authURL = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=" + encName + "&serverId=" + encodedHash + preventProxy;
|
||||
|
||||
Callback<String> handler = new Callback<String>()
|
||||
@ -516,7 +529,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
userCon.setCompressionThreshold( BungeeCord.getInstance().config.getCompressionThreshold() );
|
||||
userCon.init();
|
||||
|
||||
unsafe.sendPacket( new LoginSuccess( getUniqueId().toString(), getName() ) ); // With dashes in between
|
||||
unsafe.sendPacket( new LoginSuccess( getUniqueId(), getName() ) );
|
||||
ch.setProtocol( Protocol.GAME );
|
||||
|
||||
ch.getHandle().pipeline().get( HandlerBoss.class ).setHandler( new UpstreamBridge( bungee, userCon ) );
|
||||
@ -556,13 +569,19 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
@Override
|
||||
public void disconnect(String reason)
|
||||
{
|
||||
disconnect( TextComponent.fromLegacyText( reason ) );
|
||||
if ( canSendKickMessage() )
|
||||
{
|
||||
disconnect( TextComponent.fromLegacyText( reason ) );
|
||||
} else
|
||||
{
|
||||
ch.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(final BaseComponent... reason)
|
||||
{
|
||||
if ( thisState != State.STATUS && thisState != State.PING )
|
||||
if ( canSendKickMessage() )
|
||||
{
|
||||
ch.delayedClose( new Kick( ComponentSerializer.toString( reason ) ) );
|
||||
} else
|
||||
@ -594,6 +613,12 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getAddress()
|
||||
{
|
||||
return (InetSocketAddress) getSocketAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getSocketAddress()
|
||||
{
|
||||
return ch.getRemoteAddress();
|
||||
}
|
||||
@ -628,7 +653,20 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "[" + ( ( getName() != null ) ? getName() : getAddress() ) + "] <-> InitialHandler";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append( '[' );
|
||||
|
||||
String currentName = getName();
|
||||
if ( currentName != null )
|
||||
{
|
||||
sb.append( currentName );
|
||||
sb.append( ',' );
|
||||
}
|
||||
|
||||
sb.append( getSocketAddress() );
|
||||
sb.append( "] <-> InitialHandler" );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -4,6 +4,7 @@ import com.google.gson.Gson;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.BungeeServerInfo;
|
||||
import net.md_5.bungee.api.Callback;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.ServerPing;
|
||||
@ -65,7 +66,9 @@ public class PingHandler extends PacketHandler
|
||||
public void handle(StatusResponse statusResponse) throws Exception
|
||||
{
|
||||
Gson gson = BungeeCord.getInstance().gson;
|
||||
callback.done( gson.fromJson( statusResponse.getResponse(), ServerPing.class ), null );
|
||||
ServerPing serverPing = gson.fromJson( statusResponse.getResponse(), ServerPing.class );
|
||||
( (BungeeServerInfo) target ).cachePing( serverPing );
|
||||
callback.done( serverPing, null );
|
||||
channel.close();
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.ServerConnection.KeepAliveData;
|
||||
import net.md_5.bungee.UserConnection;
|
||||
import net.md_5.bungee.Util;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
@ -121,9 +122,12 @@ public class UpstreamBridge extends PacketHandler
|
||||
@Override
|
||||
public void handle(KeepAlive alive) throws Exception
|
||||
{
|
||||
if ( alive.getRandomId() == con.getServer().getSentPingId() )
|
||||
KeepAliveData keepAliveData = con.getServer().getKeepAlives().peek();
|
||||
|
||||
if ( keepAliveData != null && alive.getRandomId() == keepAliveData.getId() )
|
||||
{
|
||||
int newPing = (int) ( System.currentTimeMillis() - con.getSentPingTime() );
|
||||
Preconditions.checkState( keepAliveData == con.getServer().getKeepAlives().poll(), "keepalive queue mismatch" );
|
||||
int newPing = (int) ( System.currentTimeMillis() - keepAliveData.getTime() );
|
||||
con.getTabListHandler().onPingChange( newPing );
|
||||
con.setPing( newPing );
|
||||
} else
|
||||
|
@ -1,15 +1,15 @@
|
||||
package net.md_5.bungee.entitymap;
|
||||
|
||||
import com.flowpowered.nbt.stream.NBTInputStream;
|
||||
import com.google.common.base.Throwables;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.DataInputStream;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.protocol.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
import se.llbit.nbt.NamedTag;
|
||||
import se.llbit.nbt.Tag;
|
||||
|
||||
/**
|
||||
* Class to rewrite integers within packets.
|
||||
@ -57,6 +57,12 @@ public abstract class EntityMap
|
||||
case ProtocolConstants.MINECRAFT_1_14_3:
|
||||
case ProtocolConstants.MINECRAFT_1_14_4:
|
||||
return EntityMap_1_14.INSTANCE;
|
||||
case ProtocolConstants.MINECRAFT_1_15:
|
||||
case ProtocolConstants.MINECRAFT_1_15_1:
|
||||
case ProtocolConstants.MINECRAFT_1_15_2:
|
||||
return EntityMap_1_15.INSTANCE;
|
||||
case ProtocolConstants.MINECRAFT_1_16:
|
||||
return EntityMap_1_16.INSTANCE;
|
||||
}
|
||||
throw new RuntimeException( "Version " + version + " has no entity map" );
|
||||
}
|
||||
@ -249,12 +255,10 @@ public abstract class EntityMap
|
||||
DefinedPacket.readVarInt( packet );
|
||||
break;
|
||||
case 13:
|
||||
try
|
||||
Tag tag = NamedTag.read( new DataInputStream( new ByteBufInputStream( packet ) ) );
|
||||
if ( tag.isError() )
|
||||
{
|
||||
new NBTInputStream( new ByteBufInputStream( packet ), false ).readTag();
|
||||
} catch ( IOException ex )
|
||||
{
|
||||
throw Throwables.propagate( ex );
|
||||
throw new RuntimeException( tag.error() );
|
||||
}
|
||||
break;
|
||||
case 15:
|
||||
@ -297,12 +301,10 @@ public abstract class EntityMap
|
||||
{
|
||||
packet.readerIndex( position );
|
||||
|
||||
try
|
||||
Tag tag = NamedTag.read( new DataInputStream( new ByteBufInputStream( packet ) ) );
|
||||
if ( tag.isError() )
|
||||
{
|
||||
new NBTInputStream( new ByteBufInputStream( packet ), false ).readTag();
|
||||
} catch ( IOException ex )
|
||||
{
|
||||
throw Throwables.propagate( ex );
|
||||
throw new RuntimeException( tag.error() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -149,6 +149,7 @@ class EntityMap_1_10 extends EntityMap
|
||||
case 0x39 /* EntityMetadata : PacketPlayOutEntityMetadata */:
|
||||
DefinedPacket.readVarInt( packet ); // Entity ID
|
||||
rewriteMetaVarInt( packet, oldId + 1, newId + 1, 6 ); // fishing hook
|
||||
rewriteMetaVarInt( packet, oldId, newId, 13 ); // guardian beam
|
||||
break;
|
||||
}
|
||||
packet.readerIndex( readerIndex );
|
||||
|
@ -150,6 +150,7 @@ class EntityMap_1_11 extends EntityMap
|
||||
DefinedPacket.readVarInt( packet ); // Entity ID
|
||||
rewriteMetaVarInt( packet, oldId + 1, newId + 1, 6 ); // fishing hook
|
||||
rewriteMetaVarInt( packet, oldId, newId, 7 ); // fireworks (et al)
|
||||
rewriteMetaVarInt( packet, oldId, newId, 13 ); // guardian beam
|
||||
break;
|
||||
}
|
||||
packet.readerIndex( readerIndex );
|
||||
|
@ -150,6 +150,7 @@ class EntityMap_1_12 extends EntityMap
|
||||
DefinedPacket.readVarInt( packet ); // Entity ID
|
||||
rewriteMetaVarInt( packet, oldId + 1, newId + 1, 6 ); // fishing hook
|
||||
rewriteMetaVarInt( packet, oldId, newId, 7 ); // fireworks (et al)
|
||||
rewriteMetaVarInt( packet, oldId, newId, 13 ); // guardian beam
|
||||
break;
|
||||
}
|
||||
packet.readerIndex( readerIndex );
|
||||
|
@ -150,6 +150,7 @@ class EntityMap_1_12_1 extends EntityMap
|
||||
DefinedPacket.readVarInt( packet ); // Entity ID
|
||||
rewriteMetaVarInt( packet, oldId + 1, newId + 1, 6 ); // fishing hook
|
||||
rewriteMetaVarInt( packet, oldId, newId, 7 ); // fireworks (et al)
|
||||
rewriteMetaVarInt( packet, oldId, newId, 13 ); // guardian beam
|
||||
break;
|
||||
}
|
||||
packet.readerIndex( readerIndex );
|
||||
|
@ -150,6 +150,7 @@ class EntityMap_1_13 extends EntityMap
|
||||
DefinedPacket.readVarInt( packet ); // Entity ID
|
||||
rewriteMetaVarInt( packet, oldId + 1, newId + 1, 6, protocolVersion ); // fishing hook
|
||||
rewriteMetaVarInt( packet, oldId, newId, 7, protocolVersion ); // fireworks (et al)
|
||||
rewriteMetaVarInt( packet, oldId, newId, 13, protocolVersion ); // guardian beam
|
||||
break;
|
||||
}
|
||||
packet.readerIndex( readerIndex );
|
||||
|
@ -149,6 +149,7 @@ class EntityMap_1_14 extends EntityMap
|
||||
DefinedPacket.readVarInt( packet ); // Entity ID
|
||||
rewriteMetaVarInt( packet, oldId + 1, newId + 1, 7, protocolVersion ); // fishing hook
|
||||
rewriteMetaVarInt( packet, oldId, newId, 8, protocolVersion ); // fireworks (et al)
|
||||
rewriteMetaVarInt( packet, oldId, newId, 15, protocolVersion ); // guardian beam
|
||||
break;
|
||||
case 0x50 /* Entity Sound Effect : PacketPlayOutEntitySound */:
|
||||
DefinedPacket.readVarInt( packet );
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user