13
0
geforkt von Mirrors/Velocity

Merge branch 'master' into 1.13-tab-complete

Dieser Commit ist enthalten in:
Andrew Steinborn 2018-12-29 11:01:41 -05:00
Commit 76fc39660c
25 geänderte Dateien mit 183 neuen und 143 gelöschten Zeilen

Datei anzeigen

@ -11,7 +11,6 @@ import java.util.List;
import java.util.Optional;
import java.util.UUID;
import com.velocitypowered.api.network.ProtocolVersion;
import net.kyori.text.Component;
import org.checkerframework.checker.nullness.qual.Nullable;

Datei anzeigen

@ -9,24 +9,27 @@ public class Velocity {
private static final Logger logger = LogManager.getLogger(Velocity.class);
static {
// We use BufferedImage for favicons, and on macOS this puts the Java application in the dock. How inconvenient.
// Force AWT to work with its head chopped off.
// We use BufferedImage for favicons, and on macOS this puts the Java application in the dock.
// How inconvenient. Force AWT to work with its head chopped off.
System.setProperty("java.awt.headless", "true");
}
/**
* Main method that the JVM will call when {@code java -jar velocity.jar} is executed.
* @param args the arguments to the proxy
*/
public static void main(String... args) {
long startTime = System.currentTimeMillis();
final ProxyOptions options = new ProxyOptions(args);
if (options.isHelp()) {
return;
}
long startTime = System.currentTimeMillis();
VelocityServer server = new VelocityServer(options);
server.start();
Runtime.getRuntime().addShutdownHook(new Thread(() -> server.shutdown(false), "Shutdown thread"));
Runtime.getRuntime().addShutdownHook(new Thread(() -> server.shutdown(false),
"Shutdown thread"));
double bootTime = (System.currentTimeMillis() - startTime) / 1000d;
logger.info("Done ({}s)!", new DecimalFormat("#.##").format(bootTime));

Datei anzeigen

@ -144,7 +144,7 @@ public class VelocityServer implements ProxyServer {
@EnsuresNonNull({"serverKeyPair", "servers", "pluginManager", "eventManager", "scheduler",
"console", "cm", "configuration"})
public void start() {
void start() {
logger.info("Booting up {} {}...", getVersion().getName(), getVersion().getVersion());
serverKeyPair = EncryptionUtils.createRsaKeyPair(1024);
@ -160,12 +160,12 @@ public class VelocityServer implements ProxyServer {
Path configPath = Paths.get("velocity.toml");
configuration = VelocityConfiguration.read(configPath);
AnnotatedConfig
.saveConfig(configuration.dumpConfig(), configPath); // Resave config to add new values
// Resave config to add new values
AnnotatedConfig.saveConfig(configuration.dumpConfig(), configPath);
if (!configuration.validate()) {
logger.error(
"Your configuration is invalid. Velocity will refuse to start up until the errors are resolved.");
logger.error("Your configuration is invalid. Velocity will not start up until the errors "
+ "are resolved.");
LogManager.shutdown();
System.exit(1);
}

Datei anzeigen

@ -231,7 +231,6 @@ public class VelocityCommand implements Command {
}
private TextComponent componentForPlugin(PluginDescription description) {
TextComponent pluginSelf = TextComponent.of(description.getId(), TextColor.GRAY);
String pluginInfo = description.getName().orElse(description.getId())
+ description.getVersion().map(v -> " " + v).orElse("");
@ -256,7 +255,8 @@ public class VelocityCommand implements Command {
hoverText.append(TextComponent.of(pdesc));
});
return pluginSelf.hoverEvent(new HoverEvent(Action.SHOW_TEXT, hoverText.build()));
return TextComponent.of(description.getId(), TextColor.GRAY)
.hoverEvent(new HoverEvent(Action.SHOW_TEXT, hoverText.build()));
}
@Override

Datei anzeigen

@ -141,8 +141,7 @@ public abstract class AnnotatedConfig {
@SuppressWarnings("unchecked")
Map<String, ?> map = (Map<String, ?>) value;
for (Entry<String, ?> entry : map.entrySet()) {
lines.add(
escapeKeyIfNeeded(entry.getKey()) + " = " + serialize(entry.getValue())); // Save map data
lines.add(escapeKeyIfNeeded(entry.getKey()) + " = " + serialize(entry.getValue()));
}
lines.add(""); // Add empty line
continue;
@ -165,7 +164,7 @@ public abstract class AnnotatedConfig {
}
/**
* Serializes <pre>value</pre> so it could be parsed by TOML specification
* Serializes <pre>value</pre> so it can be parsed as a TOML value.
*
* @param value object to serialize
* @return Serialized object

Datei anzeigen

@ -17,6 +17,7 @@ import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
@ -32,7 +33,8 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
@ConfigKey("config-version")
private final String configVersion = "1.0";
@Comment("What port should the proxy be bound to? By default, we'll bind to all addresses on port 25577.")
@Comment("What port should the proxy be bound to? By default, we'll bind to all addresses on"
+ " port 25577.")
private String bind = "0.0.0.0:25577";
@Comment({"What should be the MOTD? This gets displayed when the player adds your server to",
@ -53,12 +55,12 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
@Comment({
"Should we forward IP addresses and other data to backend servers?",
"Available options:",
"- \"none\": No forwarding will be done. All players will appear to be connecting from the proxy",
" and will have offline-mode UUIDs.",
"- \"legacy\": Forward player IPs and UUIDs in BungeeCord-compatible fashion. Use this if you run",
" servers using Minecraft 1.12 or lower.",
"- \"modern\": Forward player IPs and UUIDs as part of the login process using Velocity's native",
" forwarding. Only applicable for Minecraft 1.13 or higher."
"- \"none\": No forwarding will be done. All players will appear to be connecting from the",
" proxy and will have offline-mode UUIDs.",
"- \"legacy\": Forward player IPs and UUIDs in a BungeeCord-compatible format. Use this if",
" you run servers using Minecraft 1.12 or lower.",
"- \"modern\": Forward player IPs and UUIDs as part of the login process using Velocity's ",
" native forwarding. Only applicable for Minecraft 1.13 or higher."
})
@ConfigKey("player-info-forwarding-mode")
private PlayerInfoForwarding playerInfoForwardingMode = PlayerInfoForwarding.NONE;
@ -68,7 +70,8 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
@ConfigKey("forwarding-secret")
private byte[] forwardingSecret = generateRandomString(12).getBytes(StandardCharsets.UTF_8);
@Comment("Announce whether or not your server supports Forge/FML. If you run a modded server, we suggest turning this on.")
@Comment({"Announce whether or not your server supports Forge. If you run a modded server, we",
"suggest turning this on."})
@ConfigKey("announce-forge")
private boolean announceForge = false;
@ -90,7 +93,7 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
@Ignore
private @Nullable Favicon favicon;
public VelocityConfiguration(Servers servers, ForcedHosts forcedHosts, Advanced advanced,
private VelocityConfiguration(Servers servers, ForcedHosts forcedHosts, Advanced advanced,
Query query) {
this.servers = servers;
this.forcedHosts = forcedHosts;
@ -114,6 +117,10 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
this.query = query;
}
/**
* Attempts to validate the configuration.
* @return {@code true} if the configuration is sound, {@code false} if not
*/
public boolean validate() {
boolean valid = true;
Logger logger = AnnotatedConfig.getLogger();
@ -136,8 +143,8 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
switch (playerInfoForwardingMode) {
case NONE:
logger.warn(
"Player info forwarding is disabled! All players will appear to be connecting from the proxy and will have offline-mode UUIDs.");
logger.warn("Player info forwarding is disabled! All players will appear to be connecting "
+ "from the proxy and will have offline-mode UUIDs.");
break;
case MODERN:
if (forwardingSecret == null || forwardingSecret.length == 0) {
@ -145,6 +152,8 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
valid = false;
}
break;
default:
break;
}
if (servers.getServers().isEmpty()) {
@ -199,16 +208,16 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
logger.error("Invalid compression level {}", advanced.compressionLevel);
valid = false;
} else if (advanced.compressionLevel == 0) {
logger.warn(
"ALL packets going through the proxy will be uncompressed. This will increase bandwidth usage.");
logger.warn("ALL packets going through the proxy will be uncompressed. This will increase "
+ "bandwidth usage.");
}
if (advanced.compressionThreshold < -1) {
logger.error("Invalid compression threshold {}", advanced.compressionLevel);
valid = false;
} else if (advanced.compressionThreshold == 0) {
logger.warn(
"ALL packets going through the proxy will be compressed. This will compromise throughput and increase CPU usage!");
logger.warn("ALL packets going through the proxy will be compressed. This will compromise "
+ "throughput and increase CPU usage!");
}
if (advanced.loginRatelimit < 0) {
@ -366,14 +375,16 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
byte[] forwardingSecret = toml.getString("forwarding-secret", "5up3r53cr3t")
.getBytes(StandardCharsets.UTF_8);
String forwardingModeName = toml.getString("player-info-forwarding-mode", "MODERN")
.toUpperCase(Locale.US);
VelocityConfiguration configuration = new VelocityConfiguration(
toml.getString("bind", "0.0.0.0:25577"),
toml.getString("motd", "&3A Velocity Server"),
toml.getLong("show-max-players", 500L).intValue(),
toml.getBoolean("online-mode", true),
toml.getBoolean("announce-forge", false),
PlayerInfoForwarding
.valueOf(toml.getString("player-info-forwarding-mode", "MODERN").toUpperCase()),
PlayerInfoForwarding.valueOf(forwardingModeName),
forwardingSecret,
servers,
forcedHosts,
@ -385,20 +396,15 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
}
private static void upgradeConfig(VelocityConfiguration configuration, Toml toml) {
switch (toml.getString("config-version", configuration.configVersion)) {
case "1.0":
//TODO: Upgrade a 1.0 config to a new version. Maybe add a recursive support in future.
break;
default:
break;
}
// Will be implemented once there has been a backwards-incompatible change in the config file
// format.
}
private static String generateRandomString(int lenght) {
private static String generateRandomString(int length) {
String chars = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890";
StringBuilder builder = new StringBuilder();
Random rnd = new Random();
for (int i = 0; i < lenght; i++) {
for (int i = 0; i < length; i++) {
builder.append(chars.charAt(rnd.nextInt(chars.length())));
}
return builder.toString();
@ -489,8 +495,8 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
Map<String, List<String>> forcedHosts = new HashMap<>();
for (Map.Entry<String, Object> entry : toml.entrySet()) {
if (entry.getValue() instanceof String) {
forcedHosts
.put(unescapeKeyIfNeeded(entry.getKey()), ImmutableList.of((String) entry.getValue()));
forcedHosts.put(unescapeKeyIfNeeded(entry.getKey()), ImmutableList.of(
(String) entry.getValue()));
} else if (entry.getValue() instanceof List) {
forcedHosts.put(unescapeKeyIfNeeded(entry.getKey()),
ImmutableList.copyOf((List<String>) entry.getValue()));
@ -532,14 +538,14 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
@ConfigKey("compression-threshold")
private int compressionThreshold = 1024;
@Comment({"How much compression should be done (from 0-9). The default is -1, which uses zlib's",
@Comment({"How much compression should be done (from 0-9). The default is -1, which uses the",
"default level of 6."})
@ConfigKey("compression-level")
private int compressionLevel = -1;
@Comment({
"How fast (in miliseconds) are clients allowed to connect after the last connection? Default: 3000",
"Disable by setting to 0"
"How fast (in milliseconds) are clients allowed to connect after the last connection? By",
"default, this is three seconds. Disable this by setting this to 0."
})
@ConfigKey("login-ratelimit")
private int loginRatelimit = 3000;
@ -610,11 +616,11 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
private static class Query {
@Comment("Whether to enable responding to GameSpy 4 query responses or not")
@Comment("Whether to enable responding to GameSpy 4 query responses or not.")
@ConfigKey("enabled")
private boolean queryEnabled = false;
@Comment("If query responding is enabled, on what port should query response listener listen on?")
@Comment("If query is enabled, on what port should the query protocol listen on?")
@ConfigKey("port")
private int queryPort = 25577;

Datei anzeigen

@ -59,6 +59,11 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
private final VelocityServer server;
private ConnectionType connectionType = ConnectionTypes.UNDETERMINED;
/**
* Initializes a new {@link MinecraftConnection} instance.
* @param channel the channel on the connection
* @param server the Velocity instance
*/
public MinecraftConnection(Channel channel, VelocityServer server) {
this.channel = channel;
this.remoteAddress = channel.remoteAddress();
@ -151,30 +156,48 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
return channel.eventLoop();
}
/**
* Writes and immediately flushes a message to the connection.
* @param msg the message to write
*/
public void write(Object msg) {
if (channel.isActive()) {
channel.writeAndFlush(msg, channel.voidPromise());
}
}
/**
* Writes, but does not flush, a message to the connection.
* @param msg the message to write
*/
public void delayedWrite(Object msg) {
if (channel.isActive()) {
channel.write(msg, channel.voidPromise());
}
}
/**
* Flushes the connection.
*/
public void flush() {
if (channel.isActive()) {
channel.flush();
}
}
/**
* Closes the connection after writing the {@code msg}.
* @param msg the message to write
*/
public void closeWith(Object msg) {
if (channel.isActive()) {
channel.writeAndFlush(msg).addListener(ChannelFutureListener.CLOSE);
}
}
/**
* Immediately closes the connection.
*/
public void close() {
if (channel.isActive()) {
channel.close();
@ -197,6 +220,10 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
return state;
}
/**
* Changes the state of the Minecraft connection.
* @param state the new state
*/
public void setState(StateRegistry state) {
this.state = state;
this.channel.pipeline().get(MinecraftEncoder.class).setState(state);
@ -207,6 +234,10 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
return protocolVersion;
}
/**
* Sets the new protocol version for the connection.
* @param protocolVersion the protocol version to use
*/
public void setProtocolVersion(ProtocolVersion protocolVersion) {
this.protocolVersion = protocolVersion;
this.nextProtocolVersion = protocolVersion;
@ -225,6 +256,10 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
return sessionHandler;
}
/**
* Sets the session handler for this connection.
* @param sessionHandler the handler to use
*/
public void setSessionHandler(MinecraftSessionHandler sessionHandler) {
if (this.sessionHandler != null) {
this.sessionHandler.deactivated();
@ -237,6 +272,11 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
Preconditions.checkState(!isClosed(), "Connection is closed.");
}
/**
* Sets the compression threshold on the connection. You are responsible for sending
* {@link com.velocitypowered.proxy.protocol.packet.SetCompression} beforehand.
* @param threshold the compression threshold to use
*/
public void setCompressionThreshold(int threshold) {
ensureOpen();
@ -255,6 +295,11 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
channel.pipeline().addBefore(MINECRAFT_ENCODER, COMPRESSION_ENCODER, encoder);
}
/**
* Enables encryption on the connection.
* @param secret the secret key negotiated between the client and the server
* @throws GeneralSecurityException if encryption can't be enabled
*/
public void enableEncryption(byte[] secret) throws GeneralSecurityException {
ensureOpen();
@ -287,7 +332,7 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
}
/**
* Gets the detected {@link ConnectionType}
* Gets the detected {@link ConnectionType}.
* @return The {@link ConnectionType}
*/
public ConnectionType getType() {
@ -295,7 +340,7 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
}
/**
* Sets the detected {@link ConnectionType}
* Sets the detected {@link ConnectionType}.
* @param connectionType The {@link ConnectionType}
*/
public void setType(ConnectionType connectionType) {

Datei anzeigen

@ -26,7 +26,7 @@ public interface BackendConnectionPhase {
}
/**
* Indicates whether the connection is considered complete
* Indicates whether the connection is considered complete.
* @return true if so
*/
default boolean consideredComplete() {

Datei anzeigen

@ -1,6 +1,7 @@
package com.velocitypowered.proxy.connection.backend;
import static com.velocitypowered.proxy.VelocityServer.GSON;
import static com.velocitypowered.proxy.connection.forge.legacy.LegacyForgeConstants.HANDSHAKE_HOSTNAME_TOKEN;
import static com.velocitypowered.proxy.network.Connections.FRAME_DECODER;
import static com.velocitypowered.proxy.network.Connections.FRAME_ENCODER;
import static com.velocitypowered.proxy.network.Connections.HANDLER;
@ -10,19 +11,19 @@ import static com.velocitypowered.proxy.network.Connections.READ_TIMEOUT;
import com.google.common.base.Preconditions;
import com.google.common.base.VerifyException;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.ConnectionRequestBuilder;
import com.velocitypowered.api.proxy.ServerConnection;
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
import com.velocitypowered.api.proxy.server.ServerInfo;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.config.PlayerInfoForwarding;
import com.velocitypowered.proxy.connection.ConnectionTypes;
import com.velocitypowered.proxy.connection.MinecraftConnection;
import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.connection.forge.legacy.LegacyForgeConstants;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.StateRegistry;
import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder;
import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder;
@ -75,22 +76,15 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
new MinecraftDecoder(ProtocolUtils.Direction.CLIENTBOUND))
.addLast(MINECRAFT_ENCODER,
new MinecraftEncoder(ProtocolUtils.Direction.SERVERBOUND));
MinecraftConnection mc = new MinecraftConnection(ch, server);
mc.setState(StateRegistry.HANDSHAKE);
mc.setAssociation(VelocityServerConnection.this);
ch.pipeline().addLast(HANDLER, mc);
}
})
.connect(registeredServer.getServerInfo().getAddress())
.addListener((ChannelFutureListener) future -> {
if (future.isSuccess()) {
connection = future.channel().pipeline().get(MinecraftConnection.class);
// This is guaranteed not to be null, but Checker Framework is whining about it anyway
if (connection == null) {
throw new VerifyException("MinecraftConnection not injected into pipeline");
}
connection = new MinecraftConnection(future.channel(), server);
connection.setState(StateRegistry.HANDSHAKE);
connection.setAssociation(VelocityServerConnection.this);
future.channel().pipeline().addLast(HANDLER, connection);
// Kick off the connection process
connection.setSessionHandler(
@ -133,21 +127,21 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
PlayerInfoForwarding forwardingMode = server.getConfiguration().getPlayerInfoForwardingMode();
// Initiate a handshake.
// Initiate the handshake.
ProtocolVersion protocolVersion = proxyPlayer.getConnection().getNextProtocolVersion();
Handshake handshake = new Handshake();
handshake.setNextStatus(StateRegistry.LOGIN_ID);
handshake.setProtocolVersion(proxyPlayer.getConnection().getNextProtocolVersion());
handshake.setProtocolVersion(protocolVersion);
if (forwardingMode == PlayerInfoForwarding.LEGACY) {
handshake.setServerAddress(createLegacyForwardingAddress());
} else if (proxyPlayer.getConnection().getType() == ConnectionTypes.LEGACY_FORGE) {
handshake.setServerAddress(handshake.getServerAddress() + LegacyForgeConstants.HANDSHAKE_HOSTNAME_TOKEN);
handshake.setServerAddress(handshake.getServerAddress() + HANDSHAKE_HOSTNAME_TOKEN);
} else {
handshake.setServerAddress(registeredServer.getServerInfo().getAddress().getHostString());
}
handshake.setPort(registeredServer.getServerInfo().getAddress().getPort());
mc.write(handshake);
ProtocolVersion protocolVersion = proxyPlayer.getConnection().getNextProtocolVersion();
mc.setProtocolVersion(protocolVersion);
mc.setState(StateRegistry.LOGIN);
mc.write(new ServerLogin(proxyPlayer.getUsername()));

Datei anzeigen

@ -4,8 +4,8 @@ import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_13;
import com.velocitypowered.api.event.connection.PluginMessageEvent;
import com.velocitypowered.api.event.player.PlayerChatEvent;
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.connection.MinecraftConnection;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
@ -24,7 +24,6 @@ import com.velocitypowered.proxy.protocol.packet.TabCompleteResponse;
import com.velocitypowered.proxy.protocol.packet.TabCompleteResponse.Offer;
import com.velocitypowered.proxy.protocol.packet.TitlePacket;
import com.velocitypowered.proxy.protocol.util.PluginMessageUtil;
import com.velocitypowered.proxy.util.ThrowableUtils;
import io.netty.buffer.ByteBuf;
import java.util.ArrayDeque;
import java.util.ArrayList;
@ -201,18 +200,15 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
knownChannels.removeAll(channels);
backendConn.write(packet);
} else if (PluginMessageUtil.isMcBrand(packet)) {
PluginMessage rewritten = PluginMessageUtil.rewriteMinecraftBrand(packet, server.getVersion());
backendConn.write(rewritten);
backendConn.write(PluginMessageUtil.rewriteMinecraftBrand(packet, server.getVersion()));
} else if (!player.getPhase().handle(player, this, packet)) {
if (!player.getPhase().consideredComplete()
|| !serverConn.getPhase().consideredComplete()) {
// The client is trying to send messages too early. This is primarily caused by mods, but
// it's further aggravated by Velocity. To work around these issues, we will queue any
// non-FML handshake messages to be sent once the FML handshake has completed or the JoinGame
// packet has been received by the proxy, whichever comes first.
loginPluginMessages.add(packet);
if (!player.getPhase().consideredComplete() || !serverConn.getPhase()
.consideredComplete()) {
// The client is trying to send messages too early. This is primarily caused by mods, but
// it's further aggravated by Velocity. To work around these issues, we will queue any
// non-FML handshake messages to be sent once the FML handshake has completed or the
// JoinGame packet has been received by the proxy, whichever comes first.
loginPluginMessages.add(packet);
} else {
ChannelIdentifier id = server.getChannelRegistrar().getFromId(packet.getChannel());
if (id == null) {
@ -265,11 +261,8 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
@Override
public void exception(Throwable throwable) {
player.disconnect(TextComponent.builder()
.content("An exception occurred in your connection: ")
.color(TextColor.RED)
.append(TextComponent.of(ThrowableUtils.briefDescription(throwable), TextColor.WHITE))
.build());
player.disconnect(TextComponent.of("Your connection has encountered an error. Try again later.",
TextColor.RED));
}
@Override

Datei anzeigen

@ -10,6 +10,7 @@ import com.velocitypowered.api.event.player.KickedFromServerEvent.RedirectPlayer
import com.velocitypowered.api.event.player.PlayerModInfoEvent;
import com.velocitypowered.api.event.player.PlayerSettingsChangedEvent;
import com.velocitypowered.api.event.player.ServerPreConnectEvent;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.permission.PermissionFunction;
import com.velocitypowered.api.permission.PermissionProvider;
import com.velocitypowered.api.permission.Tristate;
@ -22,7 +23,6 @@ import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.util.GameProfile;
import com.velocitypowered.api.util.MessagePosition;
import com.velocitypowered.api.util.ModInfo;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.util.title.TextTitle;
import com.velocitypowered.api.util.title.Title;
import com.velocitypowered.api.util.title.Titles;
@ -41,7 +41,6 @@ import com.velocitypowered.proxy.protocol.packet.PluginMessage;
import com.velocitypowered.proxy.protocol.packet.TitlePacket;
import com.velocitypowered.proxy.server.VelocityRegisteredServer;
import com.velocitypowered.proxy.tablist.VelocityTabList;
import com.velocitypowered.proxy.util.ThrowableUtils;
import java.net.InetSocketAddress;
import java.util.Collections;
import java.util.List;
@ -383,8 +382,8 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
public Optional<RegisteredServer> getNextServerToTry() {
if (serversToTry == null) {
String virtualHostStr = getVirtualHost().map(InetSocketAddress::getHostString).orElse("");
serversToTry = server.getConfiguration().getForcedHosts()
.getOrDefault(virtualHostStr, Collections.emptyList());
serversToTry = server.getConfiguration().getForcedHosts().getOrDefault(virtualHostStr,
Collections.emptyList());
}
if (serversToTry.isEmpty()) {

Datei anzeigen

@ -128,7 +128,7 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
private ConnectionType checkForForge(Handshake handshake) {
// Determine if we're using Forge (1.8 to 1.12, may not be the case in 1.13).
if (handshake.getServerAddress().endsWith(LegacyForgeConstants.HANDSHAKE_HOSTNAME_TOKEN)
&& handshake.getProtocolVersion().getProtocol() < ProtocolVersion.MINECRAFT_1_13.getProtocol()) {
&& handshake.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_13) < 0) {
return ConnectionTypes.LEGACY_FORGE;
} else {
// For later: See if we can determine Forge 1.13+ here, else this will need to be UNDETERMINED

Datei anzeigen

@ -4,6 +4,8 @@ import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_13;
import static com.velocitypowered.proxy.VelocityServer.GSON;
import static com.velocitypowered.proxy.connection.VelocityConstants.EMPTY_BYTE_ARRAY;
import static com.velocitypowered.proxy.connection.VelocityConstants.VELOCITY_IP_FORWARDING_CHANNEL;
import static com.velocitypowered.proxy.util.EncryptionUtils.decryptRsa;
import static com.velocitypowered.proxy.util.EncryptionUtils.generateServerId;
import com.google.common.base.Preconditions;
import com.google.common.net.UrlEscapers;
@ -109,16 +111,13 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
try {
KeyPair serverKeyPair = server.getServerKeyPair();
byte[] decryptedVerifyToken = EncryptionUtils
.decryptRsa(serverKeyPair, packet.getVerifyToken());
byte[] decryptedVerifyToken = decryptRsa(serverKeyPair, packet.getVerifyToken());
if (!Arrays.equals(verify, decryptedVerifyToken)) {
throw new IllegalStateException("Unable to successfully decrypt the verification token.");
}
byte[] decryptedSharedSecret = EncryptionUtils
.decryptRsa(serverKeyPair, packet.getSharedSecret());
String serverId = EncryptionUtils
.generateServerId(decryptedSharedSecret, serverKeyPair.getPublic());
byte[] decryptedSharedSecret = decryptRsa(serverKeyPair, packet.getSharedSecret());
String serverId = generateServerId(decryptedSharedSecret, serverKeyPair.getPublic());
String playerIp = ((InetSocketAddress) inbound.getRemoteAddress()).getHostString();
String url = String.format(MOJANG_HASJOINED_URL,

Datei anzeigen

@ -6,7 +6,7 @@ import com.velocitypowered.proxy.connection.ConnectionTypes;
import com.velocitypowered.proxy.connection.util.ConnectionTypeImpl;
/**
* Contains extra logic for {@link ConnectionTypes#LEGACY_FORGE}
* Contains extra logic for {@link ConnectionTypes#LEGACY_FORGE}.
*/
public class LegacyForgeConnectionType extends ConnectionTypeImpl {
@ -18,7 +18,8 @@ public class LegacyForgeConnectionType extends ConnectionTypeImpl {
}
@Override
public GameProfile addGameProfileTokensIfRequired(GameProfile original, PlayerInfoForwarding forwardingType) {
public GameProfile addGameProfileTokensIfRequired(GameProfile original,
PlayerInfoForwarding forwardingType) {
// We can't forward the FML token to the server when we are running in legacy forwarding mode,
// since both use the "hostname" field in the handshake. We add a special property to the
// profile instead, which will be ignored by non-Forge servers and can be intercepted by a

Datei anzeigen

@ -48,7 +48,7 @@ public class LegacyForgeConstants {
static final int REGISTRY_DISCRIMINATOR = 3;
/**
* The form of the data for the reset packet
* The payload for the reset packet.
*/
static final byte[] FORGE_LEGACY_HANDSHAKE_RESET_DATA = new byte[]{RESET_DATA_DISCRIMINATOR, 0};

Datei anzeigen

@ -15,7 +15,7 @@ import javax.annotation.Nullable;
public enum LegacyForgeHandshakeBackendPhase implements BackendConnectionPhase {
/**
* Dummy phase for use with {@link BackendConnectionPhases#UNKNOWN}
* Dummy phase for use with {@link BackendConnectionPhases#UNKNOWN}.
*/
NOT_STARTED(LegacyForgeConstants.SERVER_HELLO_DISCRIMINATOR) {
@Override

Datei anzeigen

@ -11,14 +11,13 @@ import java.util.List;
import javax.annotation.Nullable;
/**
* Allows for simple tracking of the phase that the Legacy
* Forge handshake is in
* Allows for simple tracking of the phase that the Legacy Forge handshake is in.
*/
public enum LegacyForgeHandshakeClientPhase implements ClientConnectionPhase {
/**
* No handshake packets have yet been sent.
* Transition to {@link #HELLO} when the ClientHello is sent.
* No handshake packets have yet been sent. Transition to {@link #HELLO} when the ClientHello
* is sent.
*/
NOT_STARTED(LegacyForgeConstants.CLIENT_HELLO_DISCRIMINATOR) {
@Override
@ -49,8 +48,8 @@ public enum LegacyForgeHandshakeClientPhase implements ClientConnectionPhase {
},
/**
* Client and Server exchange pleasantries.
* Transition to {@link #MOD_LIST} when the ModList is sent.
* Client and Server exchange pleasantries. Transition to {@link #MOD_LIST} when the ModList is
* sent.
*/
HELLO(LegacyForgeConstants.MOD_LIST_DISCRIMINATOR) {
@Override
@ -202,7 +201,7 @@ public enum LegacyForgeHandshakeClientPhase implements ClientConnectionPhase {
}
/**
* Handles the phase tasks
* Handles the phase tasks.
*
* @param player The player
* @param handler The {@link ClientPlaySessionHandler} that is handling

Datei anzeigen

@ -1,5 +1,9 @@
package com.velocitypowered.proxy.connection.forge.legacy;
import static com.velocitypowered.proxy.connection.forge.legacy.LegacyForgeConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL;
import static com.velocitypowered.proxy.connection.forge.legacy.LegacyForgeConstants.FORGE_LEGACY_HANDSHAKE_RESET_DATA;
import static com.velocitypowered.proxy.connection.forge.legacy.LegacyForgeConstants.MOD_LIST_DISCRIMINATOR;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.velocitypowered.api.util.ModInfo;
@ -16,20 +20,16 @@ class LegacyForgeUtil {
}
/**
* Gets the discriminator from the FML|HS packet (the first byte in the data)
* Gets the discriminator from the FML|HS packet (the first byte in the data).
*
* @param message The message to analyse
* @return The discriminator
*/
static byte getHandshakePacketDiscriminator(PluginMessage message) {
Preconditions.checkArgument(
message.getChannel().equals(LegacyForgeConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL));
ByteBuf buf = Unpooled.wrappedBuffer(message.getData());
try {
return buf.readByte();
} finally {
buf.release();
}
Preconditions.checkArgument(message.getChannel().equals(FORGE_LEGACY_HANDSHAKE_CHANNEL));
byte[] data = message.getData();
Preconditions.checkArgument(data.length >= 1);
return data[0];
}
/**
@ -41,14 +41,14 @@ class LegacyForgeUtil {
static List<ModInfo.Mod> readModList(PluginMessage message) {
Preconditions.checkNotNull(message, "message");
Preconditions
.checkArgument(message.getChannel().equals(LegacyForgeConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL),
.checkArgument(message.getChannel().equals(FORGE_LEGACY_HANDSHAKE_CHANNEL),
"message is not a FML HS plugin message");
ByteBuf byteBuf = Unpooled.wrappedBuffer(message.getData());
try {
byte discriminator = byteBuf.readByte();
if (discriminator == LegacyForgeConstants.MOD_LIST_DISCRIMINATOR) {
if (discriminator == MOD_LIST_DISCRIMINATOR) {
ImmutableList.Builder<ModInfo.Mod> mods = ImmutableList.builder();
int modCount = ProtocolUtils.readVarInt(byteBuf);
@ -74,8 +74,8 @@ class LegacyForgeUtil {
*/
static PluginMessage resetPacket() {
PluginMessage msg = new PluginMessage();
msg.setChannel(LegacyForgeConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL);
msg.setData(LegacyForgeConstants.FORGE_LEGACY_HANDSHAKE_RESET_DATA.clone());
msg.setChannel(FORGE_LEGACY_HANDSHAKE_CHANNEL);
msg.setData(FORGE_LEGACY_HANDSHAKE_RESET_DATA.clone());
return msg;
}
}

Datei anzeigen

@ -15,6 +15,11 @@ public class ConnectionRequestResults {
throw new AssertionError();
}
/**
* Returns a plain result (one with a status but no reason).
* @param status the status to use
* @return the result
*/
public static ConnectionRequestBuilder.Result plainResult(
ConnectionRequestBuilder.Status status) {
return new ConnectionRequestBuilder.Result() {
@ -35,6 +40,11 @@ public class ConnectionRequestResults {
return forDisconnect(deserialized);
}
/**
* Returns a disconnect result with a reason.
* @param component the reason for disconnecting from the server
* @return the result
*/
public static ConnectionRequestBuilder.Result forDisconnect(Component component) {
return new ConnectionRequestBuilder.Result() {
@Override

Datei anzeigen

@ -45,8 +45,12 @@ public class VelocityEventManager implements EventManager {
private final PluginManager pluginManager;
public VelocityEventManager(PluginManager pluginManager) {
// Expose the event executors to the plugins - required in order for the generated ASM classes
// to work.
PluginClassLoader cl = new PluginClassLoader(new URL[0]);
cl.addToClassloaders();
// Initialize the event bus.
this.bus = new SimpleEventBus<Object>(Object.class) {
@Override
protected boolean shouldPost(@NonNull Object event, @NonNull EventSubscriber<?> subscriber) {
@ -126,8 +130,8 @@ public class VelocityEventManager implements EventManager {
}
private void unregisterHandler(EventHandler<?> handler) {
bus.unregister(s -> s instanceof KyoriToVelocityHandler &&
((KyoriToVelocityHandler<?>) s).handler == handler);
bus.unregister(s -> s instanceof KyoriToVelocityHandler
&& ((KyoriToVelocityHandler<?>) s).handler == handler);
}
@Override

Datei anzeigen

@ -3,8 +3,8 @@ package com.velocitypowered.proxy.protocol;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import com.velocitypowered.api.util.GameProfile;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.util.GameProfile;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;

Datei anzeigen

@ -84,8 +84,8 @@ public class PluginMessageUtil {
public static PluginMessage constructChannelsPacket(ProtocolVersion protocolVersion,
Collection<String> channels) {
Preconditions.checkNotNull(channels, "channels");
String channelName = protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_13) >= 0 ? REGISTER_CHANNEL
: REGISTER_CHANNEL_LEGACY;
String channelName = protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_13) >= 0
? REGISTER_CHANNEL : REGISTER_CHANNEL_LEGACY;
PluginMessage message = new PluginMessage();
message.setChannel(channelName);
message.setData(String.join("\0", channels).getBytes(StandardCharsets.UTF_8));

Datei anzeigen

@ -1,8 +1,8 @@
package com.velocitypowered.proxy.server;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerPing;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.connection.MinecraftConnection;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;

Datei anzeigen

@ -1,11 +0,0 @@
package com.velocitypowered.proxy.util;
public class ThrowableUtils {
private ThrowableUtils() {
throw new AssertionError();
}
public static String briefDescription(Throwable throwable) {
return throwable.getClass().getSimpleName() + ": " + throwable.getMessage();
}
}

Datei anzeigen

@ -39,8 +39,8 @@ class PluginDependencyUtilsTest {
private static final PluginDescription CIRCULAR_DEPENDENCY_2 = testDescription("oval",
ImmutableList.of(new PluginDependency("circle", "", false)));
// Note: Kahn's algorithm is non-unique in its return result, although the topological sort will have the correct
// order.
// Note: Kahn's algorithm is non-unique in its return result, although the topological sort will
// have the correct order.
private static final List<PluginDescription> EXPECTED = ImmutableList.of(
NEVER_DEPENDED,
NO_DEPENDENCY_1_EXAMPLE,