From c520e04ac890c0b17972b03f5b0e92a40b7f7976 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sun, 2 Sep 2018 20:50:24 -0400 Subject: [PATCH 01/45] [BREAKING] PluginMessageEvent instead --- .../event/connection/PluginMessageEvent.java | 94 +++++++++++++++++++ .../api/proxy/messages/ChannelRegistrar.java | 8 +- .../api/proxy/messages/ChannelSide.java | 15 --- .../api/proxy/messages/MessageHandler.java | 28 ------ .../backend/BackendPlaySessionHandler.java | 16 ++-- .../client/ClientPlaySessionHandler.java | 17 ++-- .../messages/VelocityChannelRegistrar.java | 29 +----- 7 files changed, 120 insertions(+), 87 deletions(-) create mode 100644 api/src/main/java/com/velocitypowered/api/event/connection/PluginMessageEvent.java delete mode 100644 api/src/main/java/com/velocitypowered/api/proxy/messages/ChannelSide.java delete mode 100644 api/src/main/java/com/velocitypowered/api/proxy/messages/MessageHandler.java diff --git a/api/src/main/java/com/velocitypowered/api/event/connection/PluginMessageEvent.java b/api/src/main/java/com/velocitypowered/api/event/connection/PluginMessageEvent.java new file mode 100644 index 000000000..4caf3280c --- /dev/null +++ b/api/src/main/java/com/velocitypowered/api/event/connection/PluginMessageEvent.java @@ -0,0 +1,94 @@ +package com.velocitypowered.api.event.connection; + +import com.google.common.base.Preconditions; +import com.google.common.io.ByteArrayDataInput; +import com.google.common.io.ByteStreams; +import com.velocitypowered.api.event.ResultedEvent; +import com.velocitypowered.api.proxy.messages.ChannelIdentifier; +import com.velocitypowered.api.proxy.messages.ChannelMessageSink; +import com.velocitypowered.api.proxy.messages.ChannelMessageSource; +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.util.Arrays; + +/** + * This event is fired when a plugin message is sent to the proxy, either from a client ({@link com.velocitypowered.api.proxy.Player}) + * or a server ({@link com.velocitypowered.api.proxy.ServerConnection}). + */ +public class PluginMessageEvent implements ResultedEvent { + private final ChannelMessageSource source; + private final ChannelMessageSink target; + private final ChannelIdentifier identifier; + private final byte[] data; + private ForwardResult result; + + public PluginMessageEvent(ChannelMessageSource source, ChannelMessageSink target, ChannelIdentifier identifier, byte[] data) { + this.source = Preconditions.checkNotNull(source, "source"); + this.target = Preconditions.checkNotNull(target, "target"); + this.identifier = Preconditions.checkNotNull(identifier, "identifier"); + this.data = Preconditions.checkNotNull(data, "data"); + this.result = ForwardResult.forward(); + } + + @Override + public ForwardResult getResult() { + return result; + } + + @Override + public void setResult(@NonNull ForwardResult result) { + this.result = Preconditions.checkNotNull(result, "result"); + } + + public ChannelMessageSource getSource() { + return source; + } + + public ChannelMessageSink getTarget() { + return target; + } + + public ChannelIdentifier getIdentifier() { + return identifier; + } + + public byte[] getData() { + return Arrays.copyOf(data, data.length); + } + + public ByteArrayDataInput dataAsDataStream() { + return ByteStreams.newDataInput(data); + } + + /** + * A result determining whether or not to forward this message on. + */ + public static class ForwardResult implements ResultedEvent.Result { + private static final ForwardResult ALLOWED = new ForwardResult(true); + private static final ForwardResult DENIED = new ForwardResult(false); + + private final boolean allowed; + + private ForwardResult(boolean b) { + this.allowed = b; + } + + @Override + public boolean isAllowed() { + return allowed; + } + + @Override + public String toString() { + return allowed ? "forward to sink" : "handled message at proxy"; + } + + public static ForwardResult forward() { + return ALLOWED; + } + + public static ForwardResult handled() { + return DENIED; + } + } +} diff --git a/api/src/main/java/com/velocitypowered/api/proxy/messages/ChannelRegistrar.java b/api/src/main/java/com/velocitypowered/api/proxy/messages/ChannelRegistrar.java index 2d77988b5..84db8799d 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/messages/ChannelRegistrar.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/messages/ChannelRegistrar.java @@ -1,16 +1,14 @@ package com.velocitypowered.api.proxy.messages; /** - * Represents an interface to register and unregister {@link MessageHandler} instances for handling plugin messages from - * the client or the server. + * Represents an interface to register and unregister {@link ChannelIdentifier}s for the proxy to listen on. */ public interface ChannelRegistrar { /** - * Registers the specified message handler to listen for plugin messages on the specified channels. - * @param handler the handler to register + * Registers the specified message identifiers to listen on for the * @param identifiers the channel identifiers to register */ - void register(MessageHandler handler, ChannelIdentifier... identifiers); + void register(ChannelIdentifier... identifiers); /** * Unregisters the handler for the specified channel. diff --git a/api/src/main/java/com/velocitypowered/api/proxy/messages/ChannelSide.java b/api/src/main/java/com/velocitypowered/api/proxy/messages/ChannelSide.java deleted file mode 100644 index 12256f432..000000000 --- a/api/src/main/java/com/velocitypowered/api/proxy/messages/ChannelSide.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.velocitypowered.api.proxy.messages; - -/** - * Represents from "which side" of the proxy the plugin message came from. - */ -public enum ChannelSide { - /** - * The plugin message came from a server that a client was connected to. - */ - FROM_SERVER, - /** - * The plugin message came from the client. - */ - FROM_CLIENT -} diff --git a/api/src/main/java/com/velocitypowered/api/proxy/messages/MessageHandler.java b/api/src/main/java/com/velocitypowered/api/proxy/messages/MessageHandler.java deleted file mode 100644 index 70a7e5fa7..000000000 --- a/api/src/main/java/com/velocitypowered/api/proxy/messages/MessageHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.velocitypowered.api.proxy.messages; - -/** - * Represents a handler for handling plugin messages. - */ -public interface MessageHandler { - /** - * Handles an incoming plugin message. - * @param source the source of the plugin message - * @param side from where the plugin message originated - * @param identifier the channel on which the message was sent - * @param data the data inside the plugin message - * @return a {@link ForwardStatus} indicating whether or not to forward this plugin message on - */ - ForwardStatus handle(ChannelMessageSource source, ChannelSide side, ChannelIdentifier identifier, byte[] data); - - enum ForwardStatus { - /** - * Forwards this plugin message on to the client or server, depending on the {@link ChannelSide} it originated - * from. - */ - FORWARD, - /** - * Discard the plugin message and do not forward it on. - */ - HANDLED - } -} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java index 60ed678c0..8fbee6e6d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java @@ -1,8 +1,7 @@ package com.velocitypowered.proxy.connection.backend; +import com.velocitypowered.api.event.connection.PluginMessageEvent; import com.velocitypowered.api.event.player.ServerConnectedEvent; -import com.velocitypowered.api.proxy.messages.ChannelSide; -import com.velocitypowered.api.proxy.messages.MessageHandler; import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.connection.client.ClientPlaySessionHandler; import com.velocitypowered.proxy.protocol.MinecraftPacket; @@ -68,11 +67,14 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { return; } - MessageHandler.ForwardStatus status = server.getChannelRegistrar().handlePluginMessage(connection, - ChannelSide.FROM_SERVER, pm); - if (status == MessageHandler.ForwardStatus.FORWARD) { - connection.getPlayer().getConnection().write(pm); - } + PluginMessageEvent event = new PluginMessageEvent(connection, connection.getPlayer(), server.getChannelRegistrar().getFromId(pm.getChannel()), + pm.getData()); + server.getEventManager().fire(event) + .thenAcceptAsync(pme -> { + if (pme.getResult().isAllowed()) { + connection.getPlayer().getConnection().write(pm); + } + }, connection.getMinecraftConnection().getChannel().eventLoop()); } else { // Just forward the packet on. We don't have anything to handle at this time. connection.getPlayer().getConnection().write(packet); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index 9c36766ef..aa296599d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -1,8 +1,7 @@ package com.velocitypowered.proxy.connection.client; import com.velocitypowered.api.event.connection.DisconnectEvent; -import com.velocitypowered.api.proxy.messages.ChannelSide; -import com.velocitypowered.api.proxy.messages.MessageHandler; +import com.velocitypowered.api.event.connection.PluginMessageEvent; import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolConstants; @@ -235,12 +234,14 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { return; } - MessageHandler.ForwardStatus status = server.getChannelRegistrar().handlePluginMessage(player, - ChannelSide.FROM_CLIENT, packet); - if (status == MessageHandler.ForwardStatus.FORWARD) { - // We're going to forward on the original packet. - player.getConnectedServer().getMinecraftConnection().write(packet); - } + PluginMessageEvent event = new PluginMessageEvent(player, player.getConnectedServer(), + server.getChannelRegistrar().getFromId(packet.getChannel()), packet.getData()); + server.getEventManager().fire(event) + .thenAcceptAsync(pme -> { + if (pme.getResult().isAllowed()) { + player.getConnectedServer().getMinecraftConnection().write(packet); + } + }, player.getConnectedServer().getMinecraftConnection().getChannel().eventLoop()); } public Set getClientPluginMsgChannels() { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/messages/VelocityChannelRegistrar.java b/proxy/src/main/java/com/velocitypowered/proxy/messages/VelocityChannelRegistrar.java index 1fb47cce1..1536716cc 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/messages/VelocityChannelRegistrar.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/messages/VelocityChannelRegistrar.java @@ -3,9 +3,6 @@ package com.velocitypowered.proxy.messages; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.velocitypowered.api.proxy.messages.*; -import com.velocitypowered.proxy.protocol.packet.PluginMessage; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import java.util.Collection; import java.util.Map; @@ -13,39 +10,20 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; public class VelocityChannelRegistrar implements ChannelRegistrar { - private static final Logger logger = LogManager.getLogger(VelocityChannelRegistrar.class); - private final Map handlers = new ConcurrentHashMap<>(); private final Map identifierMap = new ConcurrentHashMap<>(); @Override - public void register(MessageHandler handler, ChannelIdentifier... identifiers) { + public void register(ChannelIdentifier... identifiers) { for (ChannelIdentifier identifier : identifiers) { Preconditions.checkArgument(identifier instanceof LegacyChannelIdentifier || identifier instanceof MinecraftChannelIdentifier, "identifier is unknown"); } for (ChannelIdentifier identifier : identifiers) { - handlers.put(identifier.getId(), handler); identifierMap.put(identifier.getId(), identifier); } } - public MessageHandler.ForwardStatus handlePluginMessage(ChannelMessageSource source, ChannelSide side, PluginMessage message) { - MessageHandler handler = handlers.get(message.getChannel()); - ChannelIdentifier identifier = identifierMap.get(message.getChannel()); - if (handler == null || identifier == null) { - return MessageHandler.ForwardStatus.FORWARD; - } - - try { - return handler.handle(source, side, identifier, message.getData()); - } catch (Exception e) { - logger.info("Unable to handle plugin message on channel {} for {}", message.getChannel(), source); - // In case of doubt, do not forward the message on. - return MessageHandler.ForwardStatus.HANDLED; - } - } - @Override public void unregister(ChannelIdentifier... identifiers) { for (ChannelIdentifier identifier : identifiers) { @@ -54,7 +32,6 @@ public class VelocityChannelRegistrar implements ChannelRegistrar { } for (ChannelIdentifier identifier : identifiers) { - handlers.remove(identifier.getId()); identifierMap.remove(identifier.getId()); } } @@ -73,4 +50,8 @@ public class VelocityChannelRegistrar implements ChannelRegistrar { public boolean registered(String id) { return identifierMap.containsKey(id); } + + public ChannelIdentifier getFromId(String id) { + return identifierMap.get(id); + } } From 74bf246c3958e640a183aea653d839d636ae2554 Mon Sep 17 00:00:00 2001 From: Leymooo Date: Tue, 11 Sep 2018 16:15:54 +0300 Subject: [PATCH 02/45] Add PostLoginEvent. Resolve #72 --- .../api/event/connection/PostLoginEvent.java | 29 +++++++++++ .../client/LoginSessionHandler.java | 48 ++++++++++--------- 2 files changed, 55 insertions(+), 22 deletions(-) create mode 100644 api/src/main/java/com/velocitypowered/api/event/connection/PostLoginEvent.java diff --git a/api/src/main/java/com/velocitypowered/api/event/connection/PostLoginEvent.java b/api/src/main/java/com/velocitypowered/api/event/connection/PostLoginEvent.java new file mode 100644 index 000000000..8cd3dea50 --- /dev/null +++ b/api/src/main/java/com/velocitypowered/api/event/connection/PostLoginEvent.java @@ -0,0 +1,29 @@ +package com.velocitypowered.api.event.connection; + +import com.google.common.base.Preconditions; +import com.velocitypowered.api.proxy.Player; +import org.checkerframework.checker.nullness.qual.NonNull; + +/** + * This event is fired once the player has been successfully authenticated and + * fully initialized and player will be connected to server after this event + */ +public class PostLoginEvent { + + private final Player player; + + public PostLoginEvent(@NonNull Player player) { + this.player = Preconditions.checkNotNull(player, "player"); + } + + public Player getPlayer() { + return player; + } + + @Override + public String toString() { + return "PostLoginEvent{" + + "player=" + player + + '}'; + } +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java index ff728178f..0ae515ffb 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java @@ -2,6 +2,7 @@ package com.velocitypowered.proxy.connection.client; import com.google.common.base.Preconditions; import com.velocitypowered.api.event.connection.LoginEvent; +import com.velocitypowered.api.event.connection.PostLoginEvent; import com.velocitypowered.api.event.connection.PreLoginEvent; import com.velocitypowered.api.event.connection.PreLoginEvent.PreLoginComponentResult; import com.velocitypowered.api.event.permission.PermissionsSetupEvent; @@ -39,9 +40,10 @@ import java.util.Optional; import java.util.concurrent.ThreadLocalRandom; public class LoginSessionHandler implements MinecraftSessionHandler { + private static final Logger logger = LogManager.getLogger(LoginSessionHandler.class); - private static final String MOJANG_SERVER_AUTH_URL = - "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=%s&serverId=%s&ip=%s"; + private static final String MOJANG_SERVER_AUTH_URL + = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=%s&serverId=%s&ip=%s"; private final VelocityServer server; private final MinecraftConnection inbound; @@ -193,26 +195,26 @@ public class LoginSessionHandler implements MinecraftSessionHandler { apiInbound.getVirtualHost().orElse(null)); return server.getEventManager().fire(new PermissionsSetupEvent(player, ConnectedPlayer.DEFAULT_PERMISSIONS)) - .thenCompose(event -> { - // wait for permissions to load, then set the players permission function - player.setPermissionFunction(event.createFunction(player)); - // then call & wait for the login event - return server.getEventManager().fire(new LoginEvent(player)); - }) - // then complete the connection - .thenAcceptAsync(event -> { - if (inbound.isClosed()) { - // The player was disconnected - return; - } - if (!event.getResult().isAllowed()) { - // The component is guaranteed to be provided if the connection was denied. - inbound.closeWith(Disconnect.create(event.getResult().getReason().get())); - return; - } + .thenCompose(event -> { + // wait for permissions to load, then set the players permission function + player.setPermissionFunction(event.createFunction(player)); + // then call & wait for the login event + return server.getEventManager().fire(new LoginEvent(player)); + }) + // then complete the connection + .thenAcceptAsync(event -> { + if (inbound.isClosed()) { + // The player was disconnected + return; + } + if (!event.getResult().isAllowed()) { + // The component is guaranteed to be provided if the connection was denied. + inbound.closeWith(Disconnect.create(event.getResult().getReason().get())); + return; + } - handleProxyLogin(player); - }, inbound.getChannel().eventLoop()); + handleProxyLogin(player); + }, inbound.getChannel().eventLoop()); }); } @@ -244,7 +246,9 @@ public class LoginSessionHandler implements MinecraftSessionHandler { logger.info("{} has connected", player); inbound.setSessionHandler(new InitialConnectSessionHandler(player)); - player.createConnectionRequest(toTry.get()).fireAndForget(); + server.getEventManager().fire(new PostLoginEvent(player)).thenRun(() -> { + player.createConnectionRequest(toTry.get()).fireAndForget(); + }); } @Override From 79bb43468f97399663902bb6eb64d9e380ee2547 Mon Sep 17 00:00:00 2001 From: Leymooo Date: Tue, 11 Sep 2018 17:42:24 +0300 Subject: [PATCH 03/45] remove @NonNull, revert reindentation --- .../api/event/connection/PostLoginEvent.java | 3 +- .../client/LoginSessionHandler.java | 42 +++++++++---------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/event/connection/PostLoginEvent.java b/api/src/main/java/com/velocitypowered/api/event/connection/PostLoginEvent.java index 8cd3dea50..7ecc23bbc 100644 --- a/api/src/main/java/com/velocitypowered/api/event/connection/PostLoginEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/connection/PostLoginEvent.java @@ -2,7 +2,6 @@ package com.velocitypowered.api.event.connection; import com.google.common.base.Preconditions; import com.velocitypowered.api.proxy.Player; -import org.checkerframework.checker.nullness.qual.NonNull; /** * This event is fired once the player has been successfully authenticated and @@ -12,7 +11,7 @@ public class PostLoginEvent { private final Player player; - public PostLoginEvent(@NonNull Player player) { + public PostLoginEvent(Player player) { this.player = Preconditions.checkNotNull(player, "player"); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java index 0ae515ffb..fed5cb580 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java @@ -42,8 +42,8 @@ import java.util.concurrent.ThreadLocalRandom; public class LoginSessionHandler implements MinecraftSessionHandler { private static final Logger logger = LogManager.getLogger(LoginSessionHandler.class); - private static final String MOJANG_SERVER_AUTH_URL - = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=%s&serverId=%s&ip=%s"; + private static final String MOJANG_SERVER_AUTH_URL = + "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=%s&serverId=%s&ip=%s"; private final VelocityServer server; private final MinecraftConnection inbound; @@ -195,26 +195,26 @@ public class LoginSessionHandler implements MinecraftSessionHandler { apiInbound.getVirtualHost().orElse(null)); return server.getEventManager().fire(new PermissionsSetupEvent(player, ConnectedPlayer.DEFAULT_PERMISSIONS)) - .thenCompose(event -> { - // wait for permissions to load, then set the players permission function - player.setPermissionFunction(event.createFunction(player)); - // then call & wait for the login event - return server.getEventManager().fire(new LoginEvent(player)); - }) - // then complete the connection - .thenAcceptAsync(event -> { - if (inbound.isClosed()) { - // The player was disconnected - return; - } - if (!event.getResult().isAllowed()) { - // The component is guaranteed to be provided if the connection was denied. - inbound.closeWith(Disconnect.create(event.getResult().getReason().get())); - return; - } + .thenCompose(event -> { + // wait for permissions to load, then set the players permission function + player.setPermissionFunction(event.createFunction(player)); + // then call & wait for the login event + return server.getEventManager().fire(new LoginEvent(player)); + }) + // then complete the connection + .thenAcceptAsync(event -> { + if (inbound.isClosed()) { + // The player was disconnected + return; + } + if (!event.getResult().isAllowed()) { + // The component is guaranteed to be provided if the connection was denied. + inbound.closeWith(Disconnect.create(event.getResult().getReason().get())); + return; + } - handleProxyLogin(player); - }, inbound.getChannel().eventLoop()); + handleProxyLogin(player); + }, inbound.getChannel().eventLoop()); }); } From bc86a12c57e8e36952f1927cd63f35b7024e4972 Mon Sep 17 00:00:00 2001 From: Leymooo Date: Wed, 12 Sep 2018 11:43:33 +0300 Subject: [PATCH 04/45] expand PreLoginComponentResult with force offline mode --- .../api/event/connection/PreLoginEvent.java | 25 ++++++++++++++++--- .../client/LoginSessionHandler.java | 2 +- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/event/connection/PreLoginEvent.java b/api/src/main/java/com/velocitypowered/api/event/connection/PreLoginEvent.java index ef8edfb9f..9d0620f8b 100644 --- a/api/src/main/java/com/velocitypowered/api/event/connection/PreLoginEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/connection/PreLoginEvent.java @@ -56,31 +56,41 @@ public class PreLoginEvent implements ResultedEvent Date: Wed, 12 Sep 2018 10:21:28 +0100 Subject: [PATCH 05/45] Don't fire a FML reset packet on first login, set it as required for the second join after the first. Fixes #69 --- .../connection/backend/LoginSessionHandler.java | 6 ------ .../connection/client/ClientPlaySessionHandler.java | 12 +++++++++++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java index c65f1745e..1a7f5e2df 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java @@ -82,12 +82,6 @@ public class LoginSessionHandler implements MinecraftSessionHandler { if (existingConnection == null) { // Strap on the play session handler connection.getPlayer().getConnection().setSessionHandler(new ClientPlaySessionHandler(server, connection.getPlayer())); - - // This is for legacy Forge servers - during first connection the FML handshake will transition to complete regardless - // Thus, we need to ensure that a reset packet is ALWAYS sent on first switch. - // - // The call will handle if the player is not a Forge player appropriately. - connection.getPlayer().getConnection().setCanSendLegacyFMLResetPacket(true); } else { // The previous server connection should become obsolete. // Before we remove it, if the server we are departing is modded, we must always reset the client state. diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index b7cb0f91e..d178fe7aa 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -164,9 +164,19 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { public void handleBackendJoinGame(JoinGame joinGame) { resetPingData(); // reset ping data; if (!spawned) { - // nothing special to do here + // Nothing special to do with regards to spawning the player spawned = true; player.getConnection().delayedWrite(joinGame); + + // We have something special to do for legacy Forge servers - during first connection the FML handshake + // will transition to complete regardless. Thus, we need to ensure that a reset packet is ALWAYS sent on + // first switch. + // + // As we know that calling this branch only happens on first join, we set that if we are a Forge + // client that we must reset on the next switch. + // + // The call will handle if the player is not a Forge player appropriately. + player.getConnection().setCanSendLegacyFMLResetPacket(true); } else { // Ah, this is the meat and potatoes of the whole venture! // From 6196f94adf803eab442d9e51129c1236cf55f293 Mon Sep 17 00:00:00 2001 From: Leymooo Date: Wed, 12 Sep 2018 16:28:34 +0300 Subject: [PATCH 06/45] I think we dont need this comment --- .../api/event/connection/PreLoginEvent.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/event/connection/PreLoginEvent.java b/api/src/main/java/com/velocitypowered/api/event/connection/PreLoginEvent.java index 9d0620f8b..36d7b98c0 100644 --- a/api/src/main/java/com/velocitypowered/api/event/connection/PreLoginEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/connection/PreLoginEvent.java @@ -52,7 +52,7 @@ public class PreLoginEvent implements ResultedEvent Date: Wed, 12 Sep 2018 22:41:51 -0700 Subject: [PATCH 07/45] ServerPreConnectEvent#getInfo -> getServer --- .../api/event/player/ServerPreConnectEvent.java | 12 ++++++------ .../proxy/connection/client/ConnectedPlayer.java | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/event/player/ServerPreConnectEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/ServerPreConnectEvent.java index 2d86c06f8..a91f819cd 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/ServerPreConnectEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/ServerPreConnectEvent.java @@ -50,11 +50,11 @@ public class ServerPreConnectEvent implements ResultedEvent getInfo() { - return Optional.ofNullable(info); + public Optional getServer() { + return Optional.ofNullable(server); } @Override @@ -71,7 +71,7 @@ public class ServerPreConnectEvent implements ResultedEvent Date: Thu, 13 Sep 2018 10:16:10 +0300 Subject: [PATCH 08/45] Refactor PreLoginComponentResult --- .../api/event/connection/PreLoginEvent.java | 73 ++++++++++++------- 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/event/connection/PreLoginEvent.java b/api/src/main/java/com/velocitypowered/api/event/connection/PreLoginEvent.java index 36d7b98c0..e4b4b1460 100644 --- a/api/src/main/java/com/velocitypowered/api/event/connection/PreLoginEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/connection/PreLoginEvent.java @@ -3,8 +3,10 @@ package com.velocitypowered.api.event.connection; import com.google.common.base.Preconditions; import com.velocitypowered.api.event.ResultedEvent; import com.velocitypowered.api.proxy.InboundConnection; +import java.util.Optional; import net.kyori.text.Component; +import net.kyori.text.serializer.ComponentSerializers; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -54,33 +56,35 @@ public class PreLoginEvent implements ResultedEvent reason; + + private PreLoginComponentResult(Result result, @Nullable Component reason) { + this.result = result; + this.reason = Optional.ofNullable(reason); } - private PreLoginComponentResult(@Nullable Component reason) { - super(reason == null, reason); - // Don't care about this - this.onlineMode = false; - this.forceOfflineMode = false; + @Override + public boolean isAllowed() { + return result != Result.DISALLOWED; + } + + public Optional getReason() { + return reason; } public boolean isOnlineModeAllowed() { - return this.onlineMode; + return result == Result.FORCE_ONLINE; } public boolean isForceOfflineMode() { - return forceOfflineMode; + return result == Result.FORCE_OFFLINE; } @Override @@ -91,12 +95,18 @@ public class PreLoginEvent implements ResultedEvent Date: Thu, 13 Sep 2018 10:33:27 +0100 Subject: [PATCH 09/45] Only send FML/FML|MP plugin messages if the player has joined the server. See #78 --- .../proxy/connection/VelocityConstants.java | 2 ++ .../backend/VelocityServerConnection.java | 6 ++++++ .../connection/client/ClientPlaySessionHandler.java | 13 ++++++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/VelocityConstants.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/VelocityConstants.java index b6956336b..b524b31e1 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/VelocityConstants.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/VelocityConstants.java @@ -8,6 +8,8 @@ public class VelocityConstants { public static final String VELOCITY_IP_FORWARDING_CHANNEL = "velocity:player_info"; public static final String FORGE_LEGACY_HANDSHAKE_CHANNEL = "FML|HS"; + public static final String FORGE_LEGACY_CHANNEL = "FML"; + public static final String FORGE_MULTIPART_LEGACY_CHANNEL = "FML|MP"; public static final byte[] FORGE_LEGACY_HANDSHAKE_RESET_DATA = new byte[] { -2, 0 }; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java index ceb53b9e6..59b97be24 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java @@ -127,6 +127,12 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, minecraftConnection.write(login); } + public void writeIfJoined(PluginMessage message) { + if (hasCompletedJoin) { + minecraftConnection.write(message); + } + } + public MinecraftConnection getMinecraftConnection() { return minecraftConnection; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index b7cb0f91e..137b97f71 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -4,6 +4,7 @@ import com.velocitypowered.api.event.connection.DisconnectEvent; import com.velocitypowered.api.proxy.messages.ChannelSide; import com.velocitypowered.api.proxy.messages.MessageHandler; import com.velocitypowered.proxy.VelocityServer; +import com.velocitypowered.proxy.connection.VelocityConstants; import com.velocitypowered.proxy.connection.backend.VelocityServerConnection; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolConstants; @@ -275,8 +276,18 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { MessageHandler.ForwardStatus status = server.getChannelRegistrar().handlePluginMessage(player, ChannelSide.FROM_CLIENT, packet); if (status == MessageHandler.ForwardStatus.FORWARD) { + String channel = packet.getChannel(); + // We're going to forward on the original packet. - player.getConnectedServer().getMinecraftConnection().write(packet); + // + // If we have Forge messages, we may need to drop them if the server switch has + // not completed yet. + if (channel.equals(VelocityConstants.FORGE_LEGACY_CHANNEL) + || channel.equals(VelocityConstants.FORGE_MULTIPART_LEGACY_CHANNEL)) { + player.getConnectedServer().writeIfJoined(packet); + } else { + player.getConnectedServer().getMinecraftConnection().write(packet); + } } } From 961757b481107285655a30daf114d8827ffa4fcf Mon Sep 17 00:00:00 2001 From: Leymooo Date: Thu, 13 Sep 2018 23:00:12 +0300 Subject: [PATCH 10/45] fix compile --- .../com/velocitypowered/api/event/connection/PreLoginEvent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/com/velocitypowered/api/event/connection/PreLoginEvent.java b/api/src/main/java/com/velocitypowered/api/event/connection/PreLoginEvent.java index e4b4b1460..04fdc7622 100644 --- a/api/src/main/java/com/velocitypowered/api/event/connection/PreLoginEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/connection/PreLoginEvent.java @@ -56,7 +56,7 @@ public class PreLoginEvent implements ResultedEvent Date: Thu, 13 Sep 2018 22:41:21 -0600 Subject: [PATCH 11/45] Add CONNECT_TIMEOUT_MILLIS to fix timeout errors. --- .../proxy/connection/backend/VelocityServerConnection.java | 1 + .../com/velocitypowered/proxy/network/ConnectionManager.java | 1 + 2 files changed, 2 insertions(+) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java index 59b97be24..7a52248fc 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java @@ -56,6 +56,7 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, CompletableFuture result = new CompletableFuture<>(); server.initializeGenericBootstrap() .option(ChannelOption.TCP_NODELAY, true) + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, SERVER_READ_TIMEOUT_SECONDS * 1000) .handler(new ChannelInitializer() { @Override protected void initChannel(Channel ch) throws Exception { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java b/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java index cc37d62b2..ff98ae029 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java @@ -89,6 +89,7 @@ public final class ConnectionManager { ch.pipeline().addLast(Connections.HANDLER, connection); } }) + .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, CLIENT_READ_TIMEOUT_SECONDS * 1000) .childOption(ChannelOption.TCP_NODELAY, true) .childOption(ChannelOption.IP_TOS, 0x18) .localAddress(address); From cf46659d9e6ebd2431f8574e50571f9ede2bf176 Mon Sep 17 00:00:00 2001 From: PurpleIsEverything Date: Thu, 13 Sep 2018 22:53:23 -0600 Subject: [PATCH 12/45] Change to a 5 second connection timeout. --- .../proxy/connection/backend/VelocityServerConnection.java | 3 ++- .../com/velocitypowered/proxy/network/ConnectionManager.java | 2 +- .../java/com/velocitypowered/proxy/network/Connections.java | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java index 7a52248fc..ed6b3b6a0 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java @@ -33,6 +33,7 @@ import static com.velocitypowered.proxy.network.Connections.HANDLER; import static com.velocitypowered.proxy.network.Connections.MINECRAFT_DECODER; import static com.velocitypowered.proxy.network.Connections.MINECRAFT_ENCODER; import static com.velocitypowered.proxy.network.Connections.READ_TIMEOUT; +import static com.velocitypowered.proxy.network.Connections.CONNECTION_TIMEOUT_SECONDS; import static com.velocitypowered.proxy.network.Connections.SERVER_READ_TIMEOUT_SECONDS; public class VelocityServerConnection implements MinecraftConnectionAssociation, ServerConnection { @@ -56,7 +57,7 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, CompletableFuture result = new CompletableFuture<>(); server.initializeGenericBootstrap() .option(ChannelOption.TCP_NODELAY, true) - .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, SERVER_READ_TIMEOUT_SECONDS * 1000) + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, CONNECTION_TIMEOUT_SECONDS * 1000) .handler(new ChannelInitializer() { @Override protected void initChannel(Channel ch) throws Exception { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java b/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java index ff98ae029..e1ffe129e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java @@ -89,7 +89,7 @@ public final class ConnectionManager { ch.pipeline().addLast(Connections.HANDLER, connection); } }) - .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, CLIENT_READ_TIMEOUT_SECONDS * 1000) + .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, CONNECTION_TIMEOUT_SECONDS * 1000) .childOption(ChannelOption.TCP_NODELAY, true) .childOption(ChannelOption.IP_TOS, 0x18) .localAddress(address); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java b/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java index 518a3acbe..59869eede 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java @@ -16,4 +16,5 @@ public interface Connections { int CLIENT_READ_TIMEOUT_SECONDS = 30; // client -> proxy int SERVER_READ_TIMEOUT_SECONDS = 30; // proxy -> server + int CONNECTION_TIMEOUT_SECONDS = 5; } From 0469aaa03a9c2016e9f8570726089e78924fef30 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Fri, 14 Sep 2018 01:00:56 -0400 Subject: [PATCH 13/45] Fix several invalid connection closure issues. --- .../proxy/connection/backend/BackendPlaySessionHandler.java | 4 ++-- .../proxy/connection/backend/VelocityServerConnection.java | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java index 1a011a2e8..0d0236927 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java @@ -32,7 +32,7 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { if (!connection.getPlayer().isActive()) { // Connection was left open accidentally. Close it so as to avoid "You logged in from another location" // errors. - connection.getMinecraftConnection().close(); + connection.disconnect(); return; } @@ -99,7 +99,7 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { if (!connection.getPlayer().isActive()) { // Connection was left open accidentally. Close it so as to avoid "You logged in from another location" // errors. - connection.getMinecraftConnection().close(); + connection.disconnect(); return; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java index ed6b3b6a0..0d0a4be0a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java @@ -149,8 +149,10 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, } public void disconnect() { - minecraftConnection.close(); - minecraftConnection = null; + if (minecraftConnection != null) { + minecraftConnection.close(); + minecraftConnection = null; + } } @Override From 496c579e469e5ba13e26c98bf8ae8bc7ee2a5113 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Fri, 14 Sep 2018 13:56:38 -0400 Subject: [PATCH 14/45] Drop non-FML handshake packets if the game start process is not done. --- .../proxy/connection/client/ClientPlaySessionHandler.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index 6bc44a2b0..353c2d0c4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -278,8 +278,11 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { } if (player.getConnectedServer().isLegacyForge() && !player.getConnectedServer().hasCompletedJoin()) { - // Ensure that the messages are forwarded - player.getConnectedServer().getMinecraftConnection().write(packet); + // Ensure that the FML handshake is forwarded. Do not try to forward other client-side plugin messages, as + // some mods are poorly coded and will crash if mod packets are sent during the handshake/join game process. + if (packet.getChannel().equals(VelocityConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) { + player.getConnectedServer().getMinecraftConnection().write(packet); + } return; } From 9776675b7067307a925e3ce401d33933d5b65db5 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Fri, 14 Sep 2018 14:16:32 -0400 Subject: [PATCH 15/45] Queue mod plugin messages instead. --- .../client/ClientPlaySessionHandler.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index 353c2d0c4..295b4b131 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -34,6 +34,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { private boolean spawned = false; private final List serverBossBars = new ArrayList<>(); private final Set clientPluginMsgChannels = new HashSet<>(); + private final Queue loginPluginMessages = new ArrayDeque<>(); private final VelocityServer server; public ClientPlaySessionHandler(VelocityServer server, ConnectedPlayer player) { @@ -163,7 +164,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { } public void handleBackendJoinGame(JoinGame joinGame) { - resetPingData(); // reset ping data; + resetPingData(); // reset ping data if (!spawned) { // Nothing special to do with regards to spawning the player spawned = true; @@ -221,6 +222,12 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { channel, toRegister)); } + // If we had plugin messages queued during login/FML handshake, send them now. + PluginMessage pm; + while ((pm = loginPluginMessages.poll()) != null) { + player.getConnectedServer().getMinecraftConnection().delayedWrite(pm); + } + // Flush everything player.getConnection().flush(); player.getConnectedServer().getMinecraftConnection().flush(); @@ -278,10 +285,14 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { } if (player.getConnectedServer().isLegacyForge() && !player.getConnectedServer().hasCompletedJoin()) { - // Ensure that the FML handshake is forwarded. Do not try to forward other client-side plugin messages, as - // some mods are poorly coded and will crash if mod packets are sent during the handshake/join game process. if (packet.getChannel().equals(VelocityConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) { + // Always forward the FML handshake to the remote server. player.getConnectedServer().getMinecraftConnection().write(packet); + } else { + // 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 JoinGame packet has been received by the proxy. + loginPluginMessages.add(packet); } return; } From e9568e1b6c27764a320bd6d2d708e4a017251503 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Fri, 14 Sep 2018 15:26:51 -0400 Subject: [PATCH 16/45] Do not write plugin messages from the server if the player hasn't joined --- .../connection/client/ClientPlaySessionHandler.java | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index 295b4b131..f550865d2 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -300,18 +300,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { MessageHandler.ForwardStatus status = server.getChannelRegistrar().handlePluginMessage(player, ChannelSide.FROM_CLIENT, packet); if (status == MessageHandler.ForwardStatus.FORWARD) { - String channel = packet.getChannel(); - - // We're going to forward on the original packet. - // - // If we have Forge messages, we may need to drop them if the server switch has - // not completed yet. - if (channel.equals(VelocityConstants.FORGE_LEGACY_CHANNEL) - || channel.equals(VelocityConstants.FORGE_MULTIPART_LEGACY_CHANNEL)) { - player.getConnectedServer().writeIfJoined(packet); - } else { - player.getConnectedServer().getMinecraftConnection().write(packet); - } + player.getConnectedServer().writeIfJoined(packet); } } From 2b1d55a0fcfae68661277f0311fe1f2d0990d716 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sat, 15 Sep 2018 01:16:26 -0400 Subject: [PATCH 17/45] Expose original server in ServerPreConnectEvent --- .../api/event/player/ServerPreConnectEvent.java | 11 +++++++++-- .../proxy/connection/client/ConnectedPlayer.java | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/event/player/ServerPreConnectEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/ServerPreConnectEvent.java index a91f819cd..c0ad88736 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/ServerPreConnectEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/ServerPreConnectEvent.java @@ -14,11 +14,13 @@ import java.util.Optional; */ public class ServerPreConnectEvent implements ResultedEvent { private final Player player; + private final ServerInfo originalServer; private ServerResult result; - public ServerPreConnectEvent(Player player, ServerResult result) { + public ServerPreConnectEvent(Player player, ServerInfo originalServer) { this.player = Preconditions.checkNotNull(player, "player"); - this.result = Preconditions.checkNotNull(result, "result"); + this.originalServer = Preconditions.checkNotNull(originalServer, "originalServer"); + this.result = ServerResult.allowed(originalServer); } public Player getPlayer() { @@ -35,10 +37,15 @@ public class ServerPreConnectEvent implements ResultedEvent> CONNECTION_NOTIFIER = @@ -56,13 +54,11 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, public CompletableFuture connect() { CompletableFuture result = new CompletableFuture<>(); server.initializeGenericBootstrap() - .option(ChannelOption.TCP_NODELAY, true) - .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, CONNECTION_TIMEOUT_SECONDS * 1000) .handler(new ChannelInitializer() { @Override protected void initChannel(Channel ch) throws Exception { ch.pipeline() - .addLast(READ_TIMEOUT, new ReadTimeoutHandler(SERVER_READ_TIMEOUT_SECONDS, TimeUnit.SECONDS)) + .addLast(READ_TIMEOUT, new ReadTimeoutHandler(server.getConfiguration().getReadTimeout(), TimeUnit.SECONDS)) .addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder()) .addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE) .addLast(MINECRAFT_DECODER, new MinecraftDecoder(ProtocolConstants.Direction.CLIENTBOUND)) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java b/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java index e1ffe129e..9a115a608 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java @@ -75,7 +75,7 @@ public final class ConnectionManager { @Override protected void initChannel(final Channel ch) { ch.pipeline() - .addLast(READ_TIMEOUT, new ReadTimeoutHandler(CLIENT_READ_TIMEOUT_SECONDS, TimeUnit.SECONDS)) + .addLast(READ_TIMEOUT, new ReadTimeoutHandler(server.getConfiguration().getReadTimeout(), TimeUnit.SECONDS)) .addLast(LEGACY_PING_DECODER, new LegacyPingDecoder()) .addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder()) .addLast(LEGACY_PING_ENCODER, LegacyPingEncoder.INSTANCE) @@ -89,7 +89,6 @@ public final class ConnectionManager { ch.pipeline().addLast(Connections.HANDLER, connection); } }) - .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, CONNECTION_TIMEOUT_SECONDS * 1000) .childOption(ChannelOption.TCP_NODELAY, true) .childOption(ChannelOption.IP_TOS, 0x18) .localAddress(address); @@ -126,7 +125,9 @@ public final class ConnectionManager { public Bootstrap createWorker() { return new Bootstrap() .channel(this.transportType.socketChannelClass) - .group(this.workerGroup); + .group(this.workerGroup) + .option(ChannelOption.TCP_NODELAY, true) + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, server.getConfiguration().getConnectTimeout()); } public void shutdown() { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java b/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java index 59869eede..fb248dc6a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java @@ -13,8 +13,4 @@ public interface Connections { String MINECRAFT_DECODER = "minecraft-decoder"; String MINECRAFT_ENCODER = "minecraft-encoder"; String READ_TIMEOUT = "read-timeout"; - - int CLIENT_READ_TIMEOUT_SECONDS = 30; // client -> proxy - int SERVER_READ_TIMEOUT_SECONDS = 30; // proxy -> server - int CONNECTION_TIMEOUT_SECONDS = 5; } From 84947564e432b6b3089df810c24abc54152aa39b Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sat, 15 Sep 2018 01:46:28 -0400 Subject: [PATCH 19/45] Handle unexpected disconnects without a reason. --- .../backend/BackendPlaySessionHandler.java | 14 ++++++++++++++ .../backend/VelocityServerConnection.java | 6 ++++++ .../proxy/connection/client/ConnectedPlayer.java | 15 ++++++++++----- .../proxy/connection/util/ConnectionMessages.java | 1 + 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java index 0d0236927..e62eb4615 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java @@ -6,6 +6,7 @@ import com.velocitypowered.api.proxy.messages.MessageHandler; import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.connection.VelocityConstants; import com.velocitypowered.proxy.connection.client.ClientPlaySessionHandler; +import com.velocitypowered.proxy.connection.util.ConnectionMessages; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.packet.*; @@ -44,6 +45,7 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { connection.getPlayer().getConnection().write(packet); } else if (packet instanceof Disconnect) { Disconnect original = (Disconnect) packet; + connection.disconnect(); connection.getPlayer().handleConnectionException(connection.getServerInfo(), original); } else if (packet instanceof JoinGame) { playerHandler.handleBackendJoinGame((JoinGame) packet); @@ -113,6 +115,18 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { connection.getPlayer().handleConnectionException(connection.getServerInfo(), throwable); } + public VelocityServer getServer() { + return server; + } + + @Override + public void disconnected() { + if (connection.isGracefulDisconnect()) { + return; + } + connection.getPlayer().handleConnectionException(connection.getServerInfo(), Disconnect.create(ConnectionMessages.UNEXPECTED_DISCONNECT)); + } + private boolean canForwardPluginMessage(PluginMessage message) { ClientPlaySessionHandler playerHandler = (ClientPlaySessionHandler) connection.getPlayer().getConnection().getSessionHandler(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java index 2362a27d5..496a4a686 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java @@ -44,6 +44,7 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, private MinecraftConnection minecraftConnection; private boolean legacyForge = false; private boolean hasCompletedJoin = false; + private boolean gracefulDisconnect = false; public VelocityServerConnection(ServerInfo target, ConnectedPlayer proxyPlayer, VelocityServer server) { this.serverInfo = target; @@ -148,6 +149,7 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, if (minecraftConnection != null) { minecraftConnection.close(); minecraftConnection = null; + gracefulDisconnect = true; } } @@ -181,4 +183,8 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, public void setHasCompletedJoin(boolean hasCompletedJoin) { this.hasCompletedJoin = hasCompletedJoin; } + + public boolean isGracefulDisconnect() { + return gracefulDisconnect; + } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java index 2d3bd80d9..b56b74753 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java @@ -205,14 +205,19 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { String plainTextReason = PASS_THRU_TRANSLATE.serialize(disconnectReason); if (connectedServer != null && connectedServer.getServerInfo().equals(info)) { logger.error("{}: kicked from server {}: {}", this, info.getName(), plainTextReason); + handleConnectionException(info, disconnectReason, TextComponent.builder() + .content("Kicked from " + info.getName() + ": ") + .color(TextColor.RED) + .append(disconnectReason) + .build()); } else { logger.error("{}: disconnected while connecting to {}: {}", this, info.getName(), plainTextReason); + handleConnectionException(info, disconnectReason, TextComponent.builder() + .content("Unable to connect to " + info.getName() + ": ") + .color(TextColor.RED) + .append(disconnectReason) + .build()); } - handleConnectionException(info, disconnectReason, TextComponent.builder() - .content("Unable to connect to " + info.getName() + ": ") - .color(TextColor.RED) - .append(disconnectReason) - .build()); } private void handleConnectionException(ServerInfo info, @Nullable Component kickReason, Component friendlyReason) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/util/ConnectionMessages.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/util/ConnectionMessages.java index b2ff70a41..727750d62 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/util/ConnectionMessages.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/util/ConnectionMessages.java @@ -7,6 +7,7 @@ public class ConnectionMessages { public static final TextComponent ALREADY_CONNECTED = TextComponent.of("You are already connected to this server!", TextColor.RED); public static final TextComponent IN_PROGRESS = TextComponent.of("You are already connecting to a server!", TextColor.RED); public static final TextComponent INTERNAL_SERVER_CONNECTION_ERROR = TextComponent.of("Internal server connection error"); + public static final TextComponent UNEXPECTED_DISCONNECT = TextComponent.of("Unexpectedly disconnected from server - crash?"); private ConnectionMessages() { throw new AssertionError(); From ab568405dd1394045605005baf3960209bb42a77 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sat, 15 Sep 2018 02:22:52 -0400 Subject: [PATCH 20/45] Cleaned up client plugin message logic. --- .../client/ClientPlaySessionHandler.java | 33 +++++++------------ .../protocol/util/PluginMessageUtil.java | 17 +++++++--- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index f550865d2..55b023af3 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -252,8 +252,8 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { return serverBossBars; } - public void handleClientPluginMessage(PluginMessage packet) { - if (packet.getChannel().equals("REGISTER") || packet.getChannel().equals("minecraft:register")) { + private void handleClientPluginMessage(PluginMessage packet) { + if (PluginMessageUtil.isMCRegister(packet)) { List actuallyRegistered = new ArrayList<>(); List channels = PluginMessageUtil.getChannels(packet); for (String channel : channels) { @@ -270,21 +270,13 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { PluginMessage newRegisterPacket = PluginMessageUtil.constructChannelsPacket(packet.getChannel(), actuallyRegistered); player.getConnectedServer().getMinecraftConnection().write(newRegisterPacket); } - - return; - } - - if (packet.getChannel().equals("UNREGISTER") || packet.getChannel().equals("minecraft:unregister")) { + } else if (PluginMessageUtil.isMCUnregister(packet)) { List channels = PluginMessageUtil.getChannels(packet); clientPluginMsgChannels.removeAll(channels); - } - - if (PluginMessageUtil.isMCBrand(packet)) { + player.getConnectedServer().getMinecraftConnection().write(packet); + } else if (PluginMessageUtil.isMCBrand(packet)) { player.getConnectedServer().getMinecraftConnection().write(PluginMessageUtil.rewriteMCBrand(packet)); - return; - } - - if (player.getConnectedServer().isLegacyForge() && !player.getConnectedServer().hasCompletedJoin()) { + } else if (player.getConnectedServer().isLegacyForge() && !player.getConnectedServer().hasCompletedJoin()) { if (packet.getChannel().equals(VelocityConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) { // Always forward the FML handshake to the remote server. player.getConnectedServer().getMinecraftConnection().write(packet); @@ -294,13 +286,12 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { // be sent once the JoinGame packet has been received by the proxy. loginPluginMessages.add(packet); } - return; - } - - MessageHandler.ForwardStatus status = server.getChannelRegistrar().handlePluginMessage(player, - ChannelSide.FROM_CLIENT, packet); - if (status == MessageHandler.ForwardStatus.FORWARD) { - player.getConnectedServer().writeIfJoined(packet); + } else { + MessageHandler.ForwardStatus status = server.getChannelRegistrar().handlePluginMessage(player, + ChannelSide.FROM_CLIENT, packet); + if (status == MessageHandler.ForwardStatus.FORWARD) { + player.getConnectedServer().writeIfJoined(packet); + } } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/util/PluginMessageUtil.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/util/PluginMessageUtil.java index 075058486..e3fdeab31 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/util/PluginMessageUtil.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/util/PluginMessageUtil.java @@ -20,13 +20,20 @@ public enum PluginMessageUtil { return message.getChannel().equals("MC|Brand") || message.getChannel().equals("minecraft:brand"); } + public static boolean isMCRegister(PluginMessage message) { + Preconditions.checkNotNull(message, "message"); + return message.getChannel().equals("REGISTER") || message.getChannel().equals("minecraft:register"); + } + + public static boolean isMCUnregister(PluginMessage message) { + Preconditions.checkNotNull(message, "message"); + return message.getChannel().equals("UNREGISTER") || message.getChannel().equals("minecraft:unregister"); + } + public static List getChannels(PluginMessage message) { Preconditions.checkNotNull(message, "message"); - Preconditions.checkArgument(message.getChannel().equals("REGISTER") || - message.getChannel().equals("UNREGISTER") || - message.getChannel().equals("minecraft:register") || - message.getChannel().equals("minecraft:unregister"), - "Unknown channel type " + message.getChannel()); + Preconditions.checkArgument(isMCRegister(message) || isMCUnregister(message),"Unknown channel type %s", + message.getChannel()); String channels = new String(message.getData(), StandardCharsets.UTF_8); return ImmutableList.copyOf(channels.split("\0")); } From 88b7407aaf0dabdf2a7c6bb82908b4290989dd6e Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sat, 15 Sep 2018 13:37:30 -0400 Subject: [PATCH 21/45] Fix rare NPE during server transition. Fixes #87 --- .../client/ClientPlaySessionHandler.java | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index 55b023af3..c3bf38456 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -55,6 +55,12 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { @Override public void handle(MinecraftPacket packet) { + VelocityServerConnection serverConnection = player.getConnectedServer(); + if (serverConnection == null) { + // No server connection yet, probably transitioning. + return; + } + if (packet instanceof KeepAlive) { KeepAlive keepAlive = (KeepAlive) packet; if (keepAlive.getRandomId() != lastPingID) { @@ -64,7 +70,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { } player.setPing(System.currentTimeMillis() - lastPingSent); resetPingData(); - player.getConnectedServer().getMinecraftConnection().write(packet); + serverConnection.getMinecraftConnection().write(packet); return; } @@ -112,7 +118,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { player.getConnection().write(response); } else { - player.getConnectedServer().getMinecraftConnection().write(packet); + serverConnection.getMinecraftConnection().write(packet); } } catch (Exception e) { logger.error("Unable to provide tab list completions for " + player.getUsername() + " for command '" + req.getCommand() + "'", e); @@ -127,15 +133,21 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { } // If we don't want to handle this packet, just forward it on. - if (player.getConnectedServer().hasCompletedJoin()) { - player.getConnectedServer().getMinecraftConnection().write(packet); + if (serverConnection.hasCompletedJoin()) { + serverConnection.getMinecraftConnection().write(packet); } } @Override public void handleUnknown(ByteBuf buf) { - if (player.getConnectedServer().hasCompletedJoin()) { - player.getConnectedServer().getMinecraftConnection().write(buf.retain()); + VelocityServerConnection serverConnection = player.getConnectedServer(); + if (serverConnection == null) { + // No server connection yet, probably transitioning. + return; + } + + if (serverConnection.hasCompletedJoin()) { + serverConnection.getMinecraftConnection().write(buf.retain()); } } From be0f666f4d479a341775d09dadf483966106f515 Mon Sep 17 00:00:00 2001 From: PurpleIsEverything Date: Sat, 15 Sep 2018 18:36:10 -0600 Subject: [PATCH 22/45] Allow modifying the ModInfo type. --- .../api/proxy/server/ServerPing.java | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java b/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java index 252ad77c3..069a5f7e8 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java @@ -74,6 +74,7 @@ public class ServerPing { builder.favicon = favicon; builder.nullOutModinfo = modinfo == null; if (modinfo != null) { + builder.modType = modinfo.type; builder.mods.addAll(modinfo.modList); } return builder; @@ -91,6 +92,7 @@ public class ServerPing { private int onlinePlayers; private int maximumPlayers; private final List samplePlayers = new ArrayList<>(); + private String modType; private final List mods = new ArrayList<>(); private Component description; private Favicon favicon; @@ -121,6 +123,11 @@ public class ServerPing { return this; } + public Builder modType(String modType) { + this.modType = Preconditions.checkNotNull(modType, "modType"); + return this; + } + public Builder mods(Mod... mods) { this.mods.addAll(Arrays.asList(mods)); return this; @@ -158,7 +165,7 @@ public class ServerPing { public ServerPing build() { return new ServerPing(version, nullOutPlayers ? null : new Players(onlinePlayers, maximumPlayers, samplePlayers), description, favicon, - nullOutModinfo ? null : new Modinfo(mods)); + nullOutModinfo ? null : new Modinfo(modType, mods)); } public Version getVersion() { @@ -185,6 +192,10 @@ public class ServerPing { return favicon; } + public String getModType() { + return modType; + } + public List getMods() { return mods; } @@ -196,6 +207,7 @@ public class ServerPing { ", onlinePlayers=" + onlinePlayers + ", maximumPlayers=" + maximumPlayers + ", samplePlayers=" + samplePlayers + + ", modType=" + modType + ", mods=" + mods + ", description=" + description + ", favicon=" + favicon + @@ -291,12 +303,13 @@ public class ServerPing { } public static class Modinfo { - public static final Modinfo DEFAULT = new Modinfo(ImmutableList.of()); + public static final Modinfo DEFAULT = new Modinfo("FML", ImmutableList.of()); - private final String type = "FML"; + private final String type; private final List modList; - public Modinfo(List modList) { + public Modinfo(String type, List modList) { + this.type = Preconditions.checkNotNull(type, "type"); this.modList = ImmutableList.copyOf(modList); } } From e1b2dc0d435b35aaa70941eb44ec49fb647a7a2f Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sun, 16 Sep 2018 02:26:29 -0400 Subject: [PATCH 23/45] Introduce RegisteredServer API This interface roughly maps the BungeeCord ServerInfo API. Accordingly, this is a breaking API change, as many of the server-related events and methods working with server info instances now provide/expect the RegisteredServer interface instead. --- .../event/player/KickedFromServerEvent.java | 15 +-- .../event/player/ServerConnectedEvent.java | 8 +- .../event/player/ServerPreConnectEvent.java | 17 ++-- .../api/proxy/ConnectionRequestBuilder.java | 7 +- .../com/velocitypowered/api/proxy/Player.java | 5 +- .../api/proxy/ProxyServer.java | 12 ++- .../api/proxy/ServerConnection.java | 7 ++ .../proxy/messages/ChannelMessageSink.java | 3 +- .../api/proxy/server/RegisteredServer.java | 30 ++++++ .../velocitypowered/proxy/VelocityServer.java | 13 +-- .../proxy/command/ServerCommand.java | 23 +++-- .../backend/BackendPlaySessionHandler.java | 14 +-- .../backend/VelocityServerConnection.java | 29 ++++-- .../connection/client/ConnectedPlayer.java | 67 +++++++------ .../client/LoginSessionHandler.java | 7 +- .../proxy/server/ServerMap.java | 68 +++++++++++++ .../server/VelocityRegisteredServer.java | 95 +++++++++++++++++++ .../velocitypowered/proxy/util/ServerMap.java | 56 ----------- .../proxy/util/ServerMapTest.java | 14 +-- 19 files changed, 331 insertions(+), 159 deletions(-) create mode 100644 api/src/main/java/com/velocitypowered/api/proxy/server/RegisteredServer.java create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/server/ServerMap.java create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java delete mode 100644 proxy/src/main/java/com/velocitypowered/proxy/util/ServerMap.java diff --git a/api/src/main/java/com/velocitypowered/api/event/player/KickedFromServerEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/KickedFromServerEvent.java index 04359eea8..86bce5e66 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/KickedFromServerEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/KickedFromServerEvent.java @@ -3,6 +3,7 @@ package com.velocitypowered.api.event.player; import com.google.common.base.Preconditions; import com.velocitypowered.api.event.ResultedEvent; import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.api.proxy.server.ServerInfo; import net.kyori.text.Component; import org.checkerframework.checker.nullness.qual.NonNull; @@ -13,12 +14,12 @@ import org.checkerframework.checker.nullness.qual.NonNull; */ public class KickedFromServerEvent implements ResultedEvent { private final Player player; - private final ServerInfo server; + private final RegisteredServer server; private final Component originalReason; private final boolean duringLogin; private ServerKickResult result; - public KickedFromServerEvent(Player player, ServerInfo server, Component originalReason, boolean duringLogin, Component fancyReason) { + public KickedFromServerEvent(Player player, RegisteredServer server, Component originalReason, boolean duringLogin, Component fancyReason) { this.player = Preconditions.checkNotNull(player, "player"); this.server = Preconditions.checkNotNull(server, "server"); this.originalReason = Preconditions.checkNotNull(originalReason, "originalReason"); @@ -40,7 +41,7 @@ public class KickedFromServerEvent implements ResultedEvent { private final Player player; - private final ServerInfo originalServer; + private final RegisteredServer originalServer; private ServerResult result; - public ServerPreConnectEvent(Player player, ServerInfo originalServer) { + public ServerPreConnectEvent(Player player, RegisteredServer originalServer) { this.player = Preconditions.checkNotNull(player, "player"); this.originalServer = Preconditions.checkNotNull(originalServer, "originalServer"); this.result = ServerResult.allowed(originalServer); @@ -37,7 +38,7 @@ public class ServerPreConnectEvent implements ResultedEvent getServer() { + public Optional getServer() { return Optional.ofNullable(server); } @@ -78,14 +79,14 @@ public class ServerPreConnectEvent implements ResultedEvent connect(); + CompletableFuture connect(); /** * Initiates the connection to the remote server without waiting for a result. Velocity will use generic error diff --git a/api/src/main/java/com/velocitypowered/api/proxy/Player.java b/api/src/main/java/com/velocitypowered/api/proxy/Player.java index 0ebb1fdfa..83c05a4ae 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/Player.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/Player.java @@ -4,6 +4,7 @@ import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.proxy.player.PlayerSettings; import com.velocitypowered.api.proxy.messages.ChannelMessageSink; import com.velocitypowered.api.proxy.messages.ChannelMessageSource; +import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.api.util.MessagePosition; import net.kyori.text.Component; @@ -59,10 +60,10 @@ public interface Player extends CommandSource, InboundConnection, ChannelMessage /** * Creates a new connection request so that the player can connect to another server. - * @param info the server to connect to + * @param server the server to connect to * @return a new connection request */ - ConnectionRequestBuilder createConnectionRequest(@NonNull ServerInfo info); + ConnectionRequestBuilder createConnectionRequest(@NonNull RegisteredServer server); /** * Sets the tab list header and footer for the player. diff --git a/api/src/main/java/com/velocitypowered/api/proxy/ProxyServer.java b/api/src/main/java/com/velocitypowered/api/proxy/ProxyServer.java index b4c851c58..eb2edcbe1 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/ProxyServer.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/ProxyServer.java @@ -5,6 +5,7 @@ import com.velocitypowered.api.command.CommandManager; import com.velocitypowered.api.event.EventManager; import com.velocitypowered.api.plugin.PluginManager; import com.velocitypowered.api.proxy.messages.ChannelRegistrar; +import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.api.scheduler.Scheduler; import com.velocitypowered.api.proxy.server.ServerInfo; @@ -45,23 +46,24 @@ public interface ProxyServer { int getPlayerCount(); /** - * Retrieves a registered {@link ServerInfo} instance by its name. The search is case-insensitive. + * Retrieves a registered {@link RegisteredServer} instance by its name. The search is case-insensitive. * @param name the name of the server * @return the registered server, which may be empty */ - Optional getServerInfo(String name); + Optional getServerInfo(String name); /** - * Retrieves all {@link ServerInfo}s registered with this proxy. + * Retrieves all {@link RegisteredServer}s registered with this proxy. * @return the servers registered with this proxy */ - Collection getAllServers(); + Collection getAllServers(); /** * Registers a server with this proxy. A server with this name should not already exist. * @param server the server to register + * @return the newly registered server */ - void registerServer(ServerInfo server); + RegisteredServer registerServer(ServerInfo server); /** * Unregisters this server from the proxy. diff --git a/api/src/main/java/com/velocitypowered/api/proxy/ServerConnection.java b/api/src/main/java/com/velocitypowered/api/proxy/ServerConnection.java index 5f12fb326..b800131c0 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/ServerConnection.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/ServerConnection.java @@ -2,6 +2,7 @@ package com.velocitypowered.api.proxy; import com.velocitypowered.api.proxy.messages.ChannelMessageSink; import com.velocitypowered.api.proxy.messages.ChannelMessageSource; +import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.api.proxy.server.ServerInfo; /** @@ -12,6 +13,12 @@ public interface ServerConnection extends ChannelMessageSource, ChannelMessageSi * Returns the server that this connection is connected to. * @return the server this connection is connected to */ + RegisteredServer getServer(); + + /** + * Returns the server info for this connection. + * @return the server info for this connection + */ ServerInfo getServerInfo(); /** diff --git a/api/src/main/java/com/velocitypowered/api/proxy/messages/ChannelMessageSink.java b/api/src/main/java/com/velocitypowered/api/proxy/messages/ChannelMessageSink.java index 57ebe4ea6..37f02e539 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/messages/ChannelMessageSink.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/messages/ChannelMessageSink.java @@ -8,6 +8,7 @@ public interface ChannelMessageSink { * Sends a plugin message to this target. * @param identifier the channel identifier to send the message on * @param data the data to send + * @return whether or not the message could be sent */ - void sendPluginMessage(ChannelIdentifier identifier, byte[] data); + boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data); } diff --git a/api/src/main/java/com/velocitypowered/api/proxy/server/RegisteredServer.java b/api/src/main/java/com/velocitypowered/api/proxy/server/RegisteredServer.java new file mode 100644 index 000000000..b7bf9acb5 --- /dev/null +++ b/api/src/main/java/com/velocitypowered/api/proxy/server/RegisteredServer.java @@ -0,0 +1,30 @@ +package com.velocitypowered.api.proxy.server; + +import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.proxy.messages.ChannelMessageSink; + +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +/** + * Represents a server that has been registered with the proxy. + */ +public interface RegisteredServer extends ChannelMessageSink { + /** + * Returns the {@link ServerInfo} for this server. + * @return the server info + */ + ServerInfo getServerInfo(); + + /** + * Returns a list of all the players currently connected to this server on this proxy. + * @return the players on this proxy + */ + Collection getPlayersConnected(); + + /** + * Attempts to ping the remote server and return the server list ping result. + * @return the server ping result from the server + */ + CompletableFuture ping(); +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java index d23709111..55a2ba4c7 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java @@ -10,6 +10,7 @@ import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; import com.velocitypowered.api.event.proxy.ProxyShutdownEvent; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.ProxyServer; +import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.api.util.Favicon; import com.velocitypowered.api.plugin.PluginManager; import com.velocitypowered.api.proxy.server.ServerInfo; @@ -30,7 +31,7 @@ import com.velocitypowered.proxy.scheduler.VelocityScheduler; import com.velocitypowered.proxy.util.AddressUtil; import com.velocitypowered.proxy.util.EncryptionUtils; import com.velocitypowered.proxy.util.Ratelimiter; -import com.velocitypowered.proxy.util.ServerMap; +import com.velocitypowered.proxy.server.ServerMap; import io.netty.bootstrap.Bootstrap; import net.kyori.text.Component; import net.kyori.text.TextComponent; @@ -61,7 +62,7 @@ public class VelocityServer implements ProxyServer { private VelocityConfiguration configuration; private NettyHttpClient httpClient; private KeyPair serverKeyPair; - private final ServerMap servers = new ServerMap(); + private final ServerMap servers = new ServerMap(this); private final VelocityCommandManager commandManager = new VelocityCommandManager(); private final AtomicBoolean shutdownInProgress = new AtomicBoolean(false); private boolean shutdown = false; @@ -263,19 +264,19 @@ public class VelocityServer implements ProxyServer { } @Override - public Optional getServerInfo(String name) { + public Optional getServerInfo(String name) { Preconditions.checkNotNull(name, "name"); return servers.getServer(name); } @Override - public Collection getAllServers() { + public Collection getAllServers() { return servers.getAllServers(); } @Override - public void registerServer(ServerInfo server) { - servers.register(server); + public RegisteredServer registerServer(ServerInfo server) { + return servers.register(server); } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/ServerCommand.java b/proxy/src/main/java/com/velocitypowered/proxy/command/ServerCommand.java index b42a9ed26..3707a800c 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/ServerCommand.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/ServerCommand.java @@ -6,6 +6,7 @@ import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.ServerConnection; +import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.api.proxy.server.ServerInfo; import net.kyori.text.TextComponent; import net.kyori.text.event.ClickEvent; @@ -34,7 +35,7 @@ public class ServerCommand implements Command { if (args.length == 1) { // Trying to connect to a server. String serverName = args[0]; - Optional toConnect = server.getServerInfo(serverName); + Optional toConnect = server.getServerInfo(serverName); if (!toConnect.isPresent()) { player.sendMessage(TextComponent.of("Server " + serverName + " doesn't exist.", TextColor.RED)); return; @@ -48,17 +49,19 @@ public class ServerCommand implements Command { // Assemble the list of servers as components TextComponent.Builder serverListBuilder = TextComponent.builder("Available servers: ").color(TextColor.YELLOW); - List infos = ImmutableList.copyOf(server.getAllServers()); + List infos = ImmutableList.copyOf(server.getAllServers()); for (int i = 0; i < infos.size(); i++) { - ServerInfo serverInfo = infos.get(i); - TextComponent infoComponent = TextComponent.of(serverInfo.getName()); - if (serverInfo.getName().equals(currentServer)) { + RegisteredServer rs = infos.get(i); + TextComponent infoComponent = TextComponent.of(rs.getServerInfo().getName()); + String playersText = rs.getPlayersConnected().size() + " player(s) online"; + if (rs.getServerInfo().getName().equals(currentServer)) { infoComponent = infoComponent.color(TextColor.GREEN) - .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Currently connected to this server"))); + .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, + TextComponent.of("Currently connected to this server\n" + playersText))); } else { infoComponent = infoComponent.color(TextColor.GRAY) - .clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/server " + serverInfo.getName())) - .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to connect to this server"))); + .clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/server " + rs.getServerInfo().getName())) + .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to connect to this server\n" + playersText))); } serverListBuilder.append(infoComponent); if (i != infos.size() - 1) { @@ -74,11 +77,11 @@ public class ServerCommand implements Command { public List suggest(CommandSource source, String[] currentArgs) { if (currentArgs.length == 0) { return server.getAllServers().stream() - .map(ServerInfo::getName) + .map(rs -> rs.getServerInfo().getName()) .collect(Collectors.toList()); } else if (currentArgs.length == 1) { return server.getAllServers().stream() - .map(ServerInfo::getName) + .map(rs -> rs.getServerInfo().getName()) .filter(name -> name.regionMatches(true, 0, currentArgs[0], 0, currentArgs[0].length())) .collect(Collectors.toList()); } else { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java index e62eb4615..fb7e1138d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java @@ -25,7 +25,8 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { @Override public void activated() { - server.getEventManager().fireAndForget(new ServerConnectedEvent(connection.getPlayer(), connection.getServerInfo())); + server.getEventManager().fireAndForget(new ServerConnectedEvent(connection.getPlayer(), connection.getServer())); + connection.getServer().addPlayer(connection.getPlayer()); } @Override @@ -46,7 +47,7 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { } else if (packet instanceof Disconnect) { Disconnect original = (Disconnect) packet; connection.disconnect(); - connection.getPlayer().handleConnectionException(connection.getServerInfo(), original); + connection.getPlayer().handleConnectionException(connection.getServer(), original); } else if (packet instanceof JoinGame) { playerHandler.handleBackendJoinGame((JoinGame) packet); } else if (packet instanceof BossBar) { @@ -112,7 +113,7 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { @Override public void exception(Throwable throwable) { - connection.getPlayer().handleConnectionException(connection.getServerInfo(), throwable); + connection.getPlayer().handleConnectionException(connection.getServer(), throwable); } public VelocityServer getServer() { @@ -121,10 +122,11 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { @Override public void disconnected() { - if (connection.isGracefulDisconnect()) { - return; + connection.getServer().removePlayer(connection.getPlayer()); + if (!connection.isGracefulDisconnect()) { + connection.getPlayer().handleConnectionException(connection.getServer(), Disconnect.create( + ConnectionMessages.UNEXPECTED_DISCONNECT)); } - connection.getPlayer().handleConnectionException(connection.getServerInfo(), Disconnect.create(ConnectionMessages.UNEXPECTED_DISCONNECT)); } private boolean canForwardPluginMessage(PluginMessage message) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java index 496a4a686..87f55b6e9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java @@ -4,6 +4,7 @@ import com.google.common.base.Preconditions; 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.RegisteredServer; import com.velocitypowered.proxy.config.PlayerInfoForwarding; import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation; import com.velocitypowered.proxy.protocol.ProtocolConstants; @@ -19,6 +20,7 @@ import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; +import com.velocitypowered.proxy.server.VelocityRegisteredServer; import io.netty.channel.*; import io.netty.handler.timeout.ReadTimeoutHandler; import io.netty.util.AttributeKey; @@ -38,7 +40,7 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, static final AttributeKey> CONNECTION_NOTIFIER = AttributeKey.newInstance("connection-notification-result"); - private final ServerInfo serverInfo; + private final VelocityRegisteredServer registeredServer; private final ConnectedPlayer proxyPlayer; private final VelocityServer server; private MinecraftConnection minecraftConnection; @@ -46,8 +48,8 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, private boolean hasCompletedJoin = false; private boolean gracefulDisconnect = false; - public VelocityServerConnection(ServerInfo target, ConnectedPlayer proxyPlayer, VelocityServer server) { - this.serverInfo = target; + public VelocityServerConnection(VelocityRegisteredServer registeredServer, ConnectedPlayer proxyPlayer, VelocityServer server) { + this.registeredServer = registeredServer; this.proxyPlayer = proxyPlayer; this.server = server; } @@ -72,7 +74,7 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, ch.pipeline().addLast(HANDLER, connection); } }) - .connect(serverInfo.getAddress()) + .connect(registeredServer.getServerInfo().getAddress()) .addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { @@ -94,7 +96,7 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, // BungeeCord IP forwarding is simply a special injection after the "address" in the handshake, // separated by \0 (the null byte). In order, you send the original host, the player's IP, their // UUID (undashed), and if you are in online-mode, their login properties (retrieved from Mojang). - return serverInfo.getAddress().getHostString() + "\0" + + return registeredServer.getServerInfo().getAddress().getHostString() + "\0" + proxyPlayer.getRemoteAddress().getHostString() + "\0" + proxyPlayer.getProfile().getId() + "\0" + GSON.toJson(proxyPlayer.getProfile().getProperties()); @@ -112,9 +114,9 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, } else if (proxyPlayer.getConnection().isLegacyForge()) { handshake.setServerAddress(handshake.getServerAddress() + "\0FML\0"); } else { - handshake.setServerAddress(serverInfo.getAddress().getHostString()); + handshake.setServerAddress(registeredServer.getServerInfo().getAddress().getHostString()); } - handshake.setPort(serverInfo.getAddress().getPort()); + handshake.setPort(registeredServer.getServerInfo().getAddress().getPort()); minecraftConnection.write(handshake); int protocolVersion = proxyPlayer.getConnection().getProtocolVersion(); @@ -136,8 +138,14 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, return minecraftConnection; } + @Override + public VelocityRegisteredServer getServer() { + return registeredServer; + } + + @Override public ServerInfo getServerInfo() { - return serverInfo; + return registeredServer.getServerInfo(); } @Override @@ -155,17 +163,18 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, @Override public String toString() { - return "[server connection] " + proxyPlayer.getProfile().getName() + " -> " + serverInfo.getName(); + return "[server connection] " + proxyPlayer.getProfile().getName() + " -> " + registeredServer.getServerInfo().getName(); } @Override - public void sendPluginMessage(ChannelIdentifier identifier, byte[] data) { + public boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data) { Preconditions.checkNotNull(identifier, "identifier"); Preconditions.checkNotNull(data, "data"); PluginMessage message = new PluginMessage(); message.setChannel(identifier.getId()); message.setData(data); minecraftConnection.write(message); + return true; } public boolean isLegacyForge() { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java index b56b74753..5cfe49ac4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java @@ -11,6 +11,7 @@ import com.velocitypowered.api.proxy.player.PlayerSettings; 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.RegisteredServer; import com.velocitypowered.api.util.MessagePosition; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.proxy.VelocityServer; @@ -24,6 +25,7 @@ import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.backend.VelocityServerConnection; import com.velocitypowered.proxy.protocol.packet.ClientSettings; import com.velocitypowered.proxy.protocol.packet.PluginMessage; +import com.velocitypowered.proxy.server.VelocityRegisteredServer; import com.velocitypowered.proxy.util.ThrowableUtils; import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.proxy.protocol.packet.Disconnect; @@ -159,8 +161,8 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { } @Override - public ConnectionRequestBuilder createConnectionRequest(@NonNull ServerInfo info) { - return new ConnectionRequestBuilderImpl(info); + public ConnectionRequestBuilder createConnectionRequest(@NonNull RegisteredServer server) { + return new ConnectionRequestBuilderImpl(server); } @Override @@ -184,57 +186,57 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { return connectedServer; } - public void handleConnectionException(ServerInfo info, Throwable throwable) { + public void handleConnectionException(RegisteredServer server, Throwable throwable) { String error = ThrowableUtils.briefDescription(throwable); String userMessage; - if (connectedServer != null && connectedServer.getServerInfo().equals(info)) { - userMessage = "Exception in server " + info.getName(); + if (connectedServer != null && connectedServer.getServerInfo().equals(server.getServerInfo())) { + userMessage = "Exception in server " + server.getServerInfo().getName(); } else { - logger.error("{}: unable to connect to server {}", this, info.getName(), throwable); - userMessage = "Exception connecting to server " + info.getName(); + logger.error("{}: unable to connect to server {}", this, server.getServerInfo().getName(), throwable); + userMessage = "Exception connecting to server " + server.getServerInfo().getName(); } - handleConnectionException(info, null, TextComponent.builder() + handleConnectionException(server, null, TextComponent.builder() .content(userMessage + ": ") .color(TextColor.RED) .append(TextComponent.of(error, TextColor.WHITE)) .build()); } - public void handleConnectionException(ServerInfo info, Disconnect disconnect) { + public void handleConnectionException(RegisteredServer server, Disconnect disconnect) { Component disconnectReason = ComponentSerializers.JSON.deserialize(disconnect.getReason()); String plainTextReason = PASS_THRU_TRANSLATE.serialize(disconnectReason); - if (connectedServer != null && connectedServer.getServerInfo().equals(info)) { - logger.error("{}: kicked from server {}: {}", this, info.getName(), plainTextReason); - handleConnectionException(info, disconnectReason, TextComponent.builder() - .content("Kicked from " + info.getName() + ": ") + if (connectedServer != null && connectedServer.getServerInfo().equals(server.getServerInfo())) { + logger.error("{}: kicked from server {}: {}", this, server.getServerInfo().getName(), plainTextReason); + handleConnectionException(server, disconnectReason, TextComponent.builder() + .content("Kicked from " + server.getServerInfo().getName() + ": ") .color(TextColor.RED) .append(disconnectReason) .build()); } else { - logger.error("{}: disconnected while connecting to {}: {}", this, info.getName(), plainTextReason); - handleConnectionException(info, disconnectReason, TextComponent.builder() - .content("Unable to connect to " + info.getName() + ": ") + logger.error("{}: disconnected while connecting to {}: {}", this, server.getServerInfo().getName(), plainTextReason); + handleConnectionException(server, disconnectReason, TextComponent.builder() + .content("Unable to connect to " + server.getServerInfo().getName() + ": ") .color(TextColor.RED) .append(disconnectReason) .build()); } } - private void handleConnectionException(ServerInfo info, @Nullable Component kickReason, Component friendlyReason) { - boolean alreadyConnected = connectedServer != null && connectedServer.getServerInfo().equals(info);; + private void handleConnectionException(RegisteredServer rs, @Nullable Component kickReason, Component friendlyReason) { + boolean alreadyConnected = connectedServer != null && connectedServer.getServerInfo().equals(rs.getServerInfo()); connectionInFlight = null; if (connectedServer == null) { // The player isn't yet connected to a server. - Optional nextServer = getNextServerToTry(); + Optional nextServer = getNextServerToTry(); if (nextServer.isPresent()) { createConnectionRequest(nextServer.get()).fireAndForget(); } else { connection.closeWith(Disconnect.create(friendlyReason)); } - } else if (connectedServer.getServerInfo().equals(info)) { + } else if (connectedServer.getServerInfo().equals(rs.getServerInfo())) { // Already connected to the server being disconnected from. if (kickReason != null) { - server.getEventManager().fire(new KickedFromServerEvent(this, info, kickReason, !alreadyConnected, friendlyReason)) + server.getEventManager().fire(new KickedFromServerEvent(this, rs, kickReason, !alreadyConnected, friendlyReason)) .thenAcceptAsync(event -> { if (event.getResult() instanceof KickedFromServerEvent.DisconnectPlayer) { KickedFromServerEvent.DisconnectPlayer res = (KickedFromServerEvent.DisconnectPlayer) event.getResult(); @@ -255,7 +257,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { } } - Optional getNextServerToTry() { + Optional getNextServerToTry() { List serversToTry = server.getConfiguration().getAttemptConnectionOrder(); if (tryIndex >= serversToTry.size()) { return Optional.empty(); @@ -289,7 +291,9 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { ); } - return new VelocityServerConnection(newEvent.getResult().getServer().get(), this, server).connect(); + RegisteredServer rs = newEvent.getResult().getServer().get(); + Preconditions.checkState(rs instanceof VelocityRegisteredServer, "Not a valid Velocity server."); + return new VelocityServerConnection((VelocityRegisteredServer) rs, this, server).connect(); }); } @@ -335,25 +339,26 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { } @Override - public void sendPluginMessage(ChannelIdentifier identifier, byte[] data) { + public boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data) { Preconditions.checkNotNull(identifier, "identifier"); Preconditions.checkNotNull(data, "data"); PluginMessage message = new PluginMessage(); message.setChannel(identifier.getId()); message.setData(data); connection.write(message); + return true; } private class ConnectionRequestBuilderImpl implements ConnectionRequestBuilder { - private final ServerInfo info; + private final RegisteredServer server; - ConnectionRequestBuilderImpl(ServerInfo info) { - this.info = Preconditions.checkNotNull(info, "info"); + ConnectionRequestBuilderImpl(RegisteredServer server) { + this.server = Preconditions.checkNotNull(server, "info"); } @Override - public ServerInfo getServer() { - return info; + public RegisteredServer getServer() { + return server; } @Override @@ -366,7 +371,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { connect() .whenCompleteAsync((status, throwable) -> { if (throwable != null) { - handleConnectionException(info, throwable); + handleConnectionException(server, throwable); return; } @@ -381,7 +386,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { // Ignored; the plugin probably already handled this. break; case SERVER_DISCONNECTED: - handleConnectionException(info, Disconnect.create(status.getReason().orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR))); + handleConnectionException(server, Disconnect.create(status.getReason().orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR))); break; } }, connection.getChannel().eventLoop()); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java index 63890c3f0..bf63dc63d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java @@ -8,6 +8,7 @@ import com.velocitypowered.api.event.connection.PreLoginEvent.PreLoginComponentR import com.velocitypowered.api.event.permission.PermissionsSetupEvent; import com.velocitypowered.api.event.player.GameProfileRequestEvent; import com.velocitypowered.api.proxy.InboundConnection; +import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.proxy.config.PlayerInfoForwarding; import com.velocitypowered.proxy.connection.VelocityConstants; @@ -220,7 +221,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler { } private void handleProxyLogin(ConnectedPlayer player) { - Optional toTry = player.getNextServerToTry(); + Optional toTry = player.getNextServerToTry(); if (!toTry.isPresent()) { player.close(TextComponent.of("No available servers", TextColor.RED)); return; @@ -246,9 +247,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler { logger.info("{} has connected", player); inbound.setSessionHandler(new InitialConnectSessionHandler(player)); - server.getEventManager().fire(new PostLoginEvent(player)).thenRun(() -> { - player.createConnectionRequest(toTry.get()).fireAndForget(); - }); + server.getEventManager().fire(new PostLoginEvent(player)).thenRun(() -> player.createConnectionRequest(toTry.get()).fireAndForget()); } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/ServerMap.java b/proxy/src/main/java/com/velocitypowered/proxy/server/ServerMap.java new file mode 100644 index 000000000..30835df3e --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/ServerMap.java @@ -0,0 +1,68 @@ +package com.velocitypowered.proxy.server; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.velocitypowered.api.proxy.server.RegisteredServer; +import com.velocitypowered.api.proxy.server.ServerInfo; +import com.velocitypowered.proxy.VelocityServer; + +import java.util.*; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +public class ServerMap { + private final VelocityServer server; + private final Map servers = new HashMap<>(); + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + + public ServerMap(VelocityServer server) { + this.server = server; + } + + public Optional getServer(String name) { + Preconditions.checkNotNull(name, "server"); + String lowerName = name.toLowerCase(Locale.US); + lock.readLock().lock(); + try { + return Optional.ofNullable(servers.get(lowerName)); + } finally { + lock.readLock().unlock(); + } + } + + public Collection getAllServers() { + lock.readLock().lock(); + try { + return ImmutableList.copyOf(servers.values()); + } finally { + lock.readLock().unlock(); + } + } + + public RegisteredServer register(ServerInfo serverInfo) { + Preconditions.checkNotNull(serverInfo, "serverInfo"); + String lowerName = serverInfo.getName().toLowerCase(Locale.US); + lock.writeLock().lock(); + try { + VelocityRegisteredServer rs = new VelocityRegisteredServer(server, serverInfo); + Preconditions.checkArgument(servers.putIfAbsent(lowerName, rs) == null, "Server with name %s already registered", serverInfo.getName()); + return rs; + } finally { + lock.writeLock().unlock(); + } + } + + public void unregister(ServerInfo serverInfo) { + Preconditions.checkNotNull(serverInfo, "serverInfo"); + String lowerName = serverInfo.getName().toLowerCase(Locale.US); + lock.writeLock().lock(); + try { + RegisteredServer rs = servers.get(lowerName); + Preconditions.checkArgument(rs != null, "Server with name %s is not registered!", serverInfo.getName()); + Preconditions.checkArgument(rs.getServerInfo().equals(serverInfo), "Trying to remove server %s with differing information", serverInfo.getName()); + servers.remove(lowerName); + } finally { + lock.writeLock().unlock(); + } + } +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java b/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java new file mode 100644 index 000000000..21c654957 --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java @@ -0,0 +1,95 @@ +package com.velocitypowered.proxy.server; + +import com.google.common.collect.ImmutableList; +import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.proxy.ServerConnection; +import com.velocitypowered.api.proxy.messages.ChannelIdentifier; +import com.velocitypowered.api.proxy.server.RegisteredServer; +import com.velocitypowered.api.proxy.server.ServerInfo; +import com.velocitypowered.api.proxy.server.ServerPing; +import com.velocitypowered.proxy.VelocityServer; +import com.velocitypowered.proxy.connection.client.ConnectedPlayer; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +public class VelocityRegisteredServer implements RegisteredServer { + private final VelocityServer server; + private final ServerInfo serverInfo; + private final Set players = new HashSet<>(); + private final ReadWriteLock playersLock = new ReentrantReadWriteLock(); + + public VelocityRegisteredServer(VelocityServer server, ServerInfo serverInfo) { + this.server = server; + this.serverInfo = serverInfo; + } + + @Override + public ServerInfo getServerInfo() { + return serverInfo; + } + + @Override + public Collection getPlayersConnected() { + playersLock.readLock().lock(); + try { + return ImmutableList.copyOf(players); + } finally { + playersLock.readLock().unlock(); + } + } + + @Override + public CompletableFuture ping() { + CompletableFuture p = new CompletableFuture<>(); + p.completeExceptionally(new UnsupportedOperationException("Not currently implemented.")); + return p; + } + + public void addPlayer(ConnectedPlayer player) { + playersLock.writeLock().lock(); + try { + players.add(player); + } finally { + playersLock.writeLock().unlock(); + } + } + + public void removePlayer(ConnectedPlayer player) { + playersLock.writeLock().lock(); + try { + players.remove(player); + } finally { + playersLock.writeLock().unlock(); + } + } + + @Override + public boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data) { + ServerConnection backendConnection = null; + playersLock.readLock().lock(); + try { + for (ConnectedPlayer player : players) { + if (player.getConnectedServer() != null && player.getConnectedServer().getServerInfo().equals(serverInfo)) { + backendConnection = player.getConnectedServer(); + break; + } + } + + if (backendConnection == null) { + return false; + } + } finally { + playersLock.readLock().unlock(); + } + + return backendConnection.sendPluginMessage(identifier, data); + } + + @Override + public String toString() { + return "registered server: " + serverInfo; + } +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/util/ServerMap.java b/proxy/src/main/java/com/velocitypowered/proxy/util/ServerMap.java deleted file mode 100644 index 75784ef0b..000000000 --- a/proxy/src/main/java/com/velocitypowered/proxy/util/ServerMap.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.velocitypowered.proxy.util; - -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.velocitypowered.api.proxy.server.ServerInfo; - -import java.util.*; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -public class ServerMap { - private final Map servers = new HashMap<>(); - private final ReadWriteLock lock = new ReentrantReadWriteLock(); - - public Optional getServer(String server) { - Preconditions.checkNotNull(server, "server"); - String lowerName = server.toLowerCase(Locale.US); - lock.readLock().lock(); - try { - return Optional.ofNullable(servers.get(lowerName)); - } finally { - lock.readLock().unlock(); - } - } - - public Collection getAllServers() { - lock.readLock().lock(); - try { - return ImmutableList.copyOf(servers.values()); - } finally { - lock.readLock().unlock(); - } - } - - public void register(ServerInfo server) { - Preconditions.checkNotNull(server, "server"); - String lowerName = server.getName().toLowerCase(Locale.US); - lock.writeLock().lock(); - try { - Preconditions.checkArgument(servers.putIfAbsent(lowerName, server) == null, "Server with name %s already registered", server.getName()); - } finally { - lock.writeLock().unlock(); - } - } - - public void unregister(ServerInfo server) { - Preconditions.checkNotNull(server, "server"); - String lowerName = server.getName().toLowerCase(Locale.US); - lock.writeLock().lock(); - try { - Preconditions.checkArgument(servers.remove(lowerName, server), "Server with this name is not registered!"); - } finally { - lock.writeLock().unlock(); - } - } -} diff --git a/proxy/src/test/java/com/velocitypowered/proxy/util/ServerMapTest.java b/proxy/src/test/java/com/velocitypowered/proxy/util/ServerMapTest.java index e332ed85f..ad8d3d52b 100644 --- a/proxy/src/test/java/com/velocitypowered/proxy/util/ServerMapTest.java +++ b/proxy/src/test/java/com/velocitypowered/proxy/util/ServerMapTest.java @@ -1,6 +1,8 @@ package com.velocitypowered.proxy.util; +import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.api.proxy.server.ServerInfo; +import com.velocitypowered.proxy.server.ServerMap; import org.junit.jupiter.api.Test; import java.net.InetAddress; @@ -14,18 +16,18 @@ class ServerMapTest { @Test void respectsCaseInsensitivity() { - ServerMap map = new ServerMap(); + ServerMap map = new ServerMap(null); ServerInfo info = new ServerInfo("TestServer", TEST_ADDRESS); - map.register(info); + RegisteredServer connection = map.register(info); - assertEquals(Optional.of(info), map.getServer("TestServer")); - assertEquals(Optional.of(info), map.getServer("testserver")); - assertEquals(Optional.of(info), map.getServer("TESTSERVER")); + assertEquals(Optional.of(connection), map.getServer("TestServer")); + assertEquals(Optional.of(connection), map.getServer("testserver")); + assertEquals(Optional.of(connection), map.getServer("TESTSERVER")); } @Test void rejectsRepeatedRegisterAttempts() { - ServerMap map = new ServerMap(); + ServerMap map = new ServerMap(null); ServerInfo info = new ServerInfo("TestServer", TEST_ADDRESS); map.register(info); From 8b94fe6ed2343bc3eaf06b01ff487e3edd9a552a Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sun, 16 Sep 2018 02:41:35 -0400 Subject: [PATCH 24/45] Readd missing check --- .../proxy/connection/backend/BackendPlaySessionHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java index 0f82b12eb..e0dc386af 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java @@ -92,7 +92,7 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { connection.getPlayer().getConnection().write(pm); } }, connection.getMinecraftConnection().getChannel().eventLoop()); - } else { + } else if (connection.hasCompletedJoin()) { // Just forward the packet on. We don't have anything to handle at this time. connection.getPlayer().getConnection().write(packet); } From 1f8152c3a52e482a01fa84eef45b75eae05c99d1 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sun, 16 Sep 2018 13:16:16 -0400 Subject: [PATCH 25/45] ProxyServer#getServerInfo -> ProxyServer#getServer --- .../main/java/com/velocitypowered/api/proxy/ProxyServer.java | 2 +- .../src/main/java/com/velocitypowered/proxy/VelocityServer.java | 2 +- .../java/com/velocitypowered/proxy/command/ServerCommand.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/proxy/ProxyServer.java b/api/src/main/java/com/velocitypowered/api/proxy/ProxyServer.java index eb2edcbe1..553e88c10 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/ProxyServer.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/ProxyServer.java @@ -50,7 +50,7 @@ public interface ProxyServer { * @param name the name of the server * @return the registered server, which may be empty */ - Optional getServerInfo(String name); + Optional getServer(String name); /** * Retrieves all {@link RegisteredServer}s registered with this proxy. diff --git a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java index 55a2ba4c7..b9711f915 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java @@ -264,7 +264,7 @@ public class VelocityServer implements ProxyServer { } @Override - public Optional getServerInfo(String name) { + public Optional getServer(String name) { Preconditions.checkNotNull(name, "name"); return servers.getServer(name); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/ServerCommand.java b/proxy/src/main/java/com/velocitypowered/proxy/command/ServerCommand.java index 3707a800c..2926bb038 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/ServerCommand.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/ServerCommand.java @@ -35,7 +35,7 @@ public class ServerCommand implements Command { if (args.length == 1) { // Trying to connect to a server. String serverName = args[0]; - Optional toConnect = server.getServerInfo(serverName); + Optional toConnect = server.getServer(serverName); if (!toConnect.isPresent()) { player.sendMessage(TextComponent.of("Server " + serverName + " doesn't exist.", TextColor.RED)); return; From 291069af807b5a20c09a3a4d68d0710ae37f7f27 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sun, 16 Sep 2018 13:59:44 -0400 Subject: [PATCH 26/45] Implement RegisteredServer#ping() --- .../proxy/connection/MinecraftConnection.java | 2 - .../server/VelocityRegisteredServer.java | 51 +++++++++++++- .../proxy/server/ping/PingSessionHandler.java | 67 +++++++++++++++++++ 3 files changed, 115 insertions(+), 5 deletions(-) create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/server/ping/PingSessionHandler.java diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java index b4a68dfbf..0f6844304 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -99,8 +99,6 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter { if (association != null) { logger.error("{}: exception encountered", association, cause); - } else { - logger.error("{} encountered an exception", ctx.channel().remoteAddress(), cause); } ctx.close(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java b/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java index 21c654957..18dfef0d0 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java @@ -8,13 +8,31 @@ import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.api.proxy.server.ServerPing; import com.velocitypowered.proxy.VelocityServer; +import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; +import com.velocitypowered.proxy.protocol.ProtocolConstants; +import com.velocitypowered.proxy.protocol.StateRegistry; +import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder; +import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder; +import com.velocitypowered.proxy.protocol.netty.MinecraftVarintFrameDecoder; +import com.velocitypowered.proxy.protocol.netty.MinecraftVarintLengthEncoder; +import com.velocitypowered.proxy.server.ping.PingSessionHandler; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelInitializer; +import io.netty.handler.timeout.ReadTimeoutHandler; import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; +import static com.velocitypowered.proxy.network.Connections.*; +import static com.velocitypowered.proxy.network.Connections.HANDLER; +import static com.velocitypowered.proxy.network.Connections.MINECRAFT_ENCODER; + public class VelocityRegisteredServer implements RegisteredServer { private final VelocityServer server; private final ServerInfo serverInfo; @@ -43,9 +61,36 @@ public class VelocityRegisteredServer implements RegisteredServer { @Override public CompletableFuture ping() { - CompletableFuture p = new CompletableFuture<>(); - p.completeExceptionally(new UnsupportedOperationException("Not currently implemented.")); - return p; + CompletableFuture pingFuture = new CompletableFuture<>(); + server.initializeGenericBootstrap() + .handler(new ChannelInitializer() { + @Override + protected void initChannel(Channel ch) throws Exception { + ch.pipeline() + .addLast(READ_TIMEOUT, new ReadTimeoutHandler(server.getConfiguration().getReadTimeout(), TimeUnit.SECONDS)) + .addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder()) + .addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE) + .addLast(MINECRAFT_DECODER, new MinecraftDecoder(ProtocolConstants.Direction.CLIENTBOUND)) + .addLast(MINECRAFT_ENCODER, new MinecraftEncoder(ProtocolConstants.Direction.SERVERBOUND)); + + MinecraftConnection connection = new MinecraftConnection(ch, server); + connection.setState(StateRegistry.HANDSHAKE); + ch.pipeline().addLast(HANDLER, connection); + } + }) + .connect(serverInfo.getAddress()) + .addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (future.isSuccess()) { + MinecraftConnection conn = future.channel().pipeline().get(MinecraftConnection.class); + conn.setSessionHandler(new PingSessionHandler(pingFuture, VelocityRegisteredServer.this, conn)); + } else { + pingFuture.completeExceptionally(future.cause()); + } + } + }); + return pingFuture; } public void addPlayer(ConnectedPlayer player) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/ping/PingSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/server/ping/PingSessionHandler.java new file mode 100644 index 000000000..4ed4dae44 --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/ping/PingSessionHandler.java @@ -0,0 +1,67 @@ +package com.velocitypowered.proxy.server.ping; + +import com.google.common.base.Preconditions; +import com.velocitypowered.api.proxy.server.RegisteredServer; +import com.velocitypowered.api.proxy.server.ServerPing; +import com.velocitypowered.proxy.VelocityServer; +import com.velocitypowered.proxy.connection.MinecraftConnection; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; +import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolConstants; +import com.velocitypowered.proxy.protocol.StateRegistry; +import com.velocitypowered.proxy.protocol.packet.Handshake; +import com.velocitypowered.proxy.protocol.packet.StatusRequest; +import com.velocitypowered.proxy.protocol.packet.StatusResponse; + +import java.io.IOException; +import java.util.concurrent.CompletableFuture; + +public class PingSessionHandler implements MinecraftSessionHandler { + private final CompletableFuture result; + private final RegisteredServer server; + private final MinecraftConnection connection; + private boolean completed = false; + + public PingSessionHandler(CompletableFuture result, RegisteredServer server, MinecraftConnection connection) { + this.result = result; + this.server = server; + this.connection = connection; + } + + @Override + public void activated() { + Handshake handshake = new Handshake(); + handshake.setNextStatus(StateRegistry.STATUS_ID); + handshake.setServerAddress(server.getServerInfo().getAddress().getHostString()); + handshake.setPort(server.getServerInfo().getAddress().getPort()); + handshake.setProtocolVersion(ProtocolConstants.MINIMUM_GENERIC_VERSION); + connection.write(handshake); + + connection.setState(StateRegistry.STATUS); + connection.write(new StatusRequest()); + } + + @Override + public void handle(MinecraftPacket packet) { + Preconditions.checkState(packet instanceof StatusResponse, "Did not get status response back from connection"); + + // All good! + completed = true; + connection.close(); + + ServerPing ping = VelocityServer.GSON.fromJson(((StatusResponse) packet).getStatus(), ServerPing.class); + result.complete(ping); + } + + @Override + public void disconnected() { + if (!completed) { + result.completeExceptionally(new IOException("Unexpectedly disconnected from remote server")); + } + } + + @Override + public void exception(Throwable throwable) { + result.completeExceptionally(throwable); + } +} From 2a842bffbe13d0db88d14c5ea184eefb7615a1a5 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sun, 16 Sep 2018 15:32:51 -0400 Subject: [PATCH 27/45] Add missing null check --- .../backend/BackendPlaySessionHandler.java | 21 ++++++++++++------- .../client/ClientPlaySessionHandler.java | 21 ++++++++++++------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java index e0dc386af..2785a38b9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java @@ -2,6 +2,7 @@ package com.velocitypowered.proxy.connection.backend; import com.velocitypowered.api.event.connection.PluginMessageEvent; import com.velocitypowered.api.event.player.ServerConnectedEvent; +import com.velocitypowered.api.proxy.messages.ChannelIdentifier; import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.connection.VelocityConstants; import com.velocitypowered.proxy.connection.client.ClientPlaySessionHandler; @@ -84,14 +85,18 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { return; } - PluginMessageEvent event = new PluginMessageEvent(connection, connection.getPlayer(), server.getChannelRegistrar().getFromId(pm.getChannel()), - pm.getData()); - server.getEventManager().fire(event) - .thenAcceptAsync(pme -> { - if (pme.getResult().isAllowed()) { - connection.getPlayer().getConnection().write(pm); - } - }, connection.getMinecraftConnection().getChannel().eventLoop()); + ChannelIdentifier id = server.getChannelRegistrar().getFromId(pm.getChannel()); + if (id == null) { + connection.getPlayer().getConnection().write(pm); + } else { + PluginMessageEvent event = new PluginMessageEvent(connection, connection.getPlayer(), id, pm.getData()); + server.getEventManager().fire(event) + .thenAcceptAsync(pme -> { + if (pme.getResult().isAllowed()) { + connection.getPlayer().getConnection().write(pm); + } + }, connection.getMinecraftConnection().getChannel().eventLoop()); + } } else if (connection.hasCompletedJoin()) { // Just forward the packet on. We don't have anything to handle at this time. connection.getPlayer().getConnection().write(packet); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index b5a88ee55..836481fba 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -2,6 +2,7 @@ package com.velocitypowered.proxy.connection.client; import com.velocitypowered.api.event.connection.DisconnectEvent; import com.velocitypowered.api.event.connection.PluginMessageEvent; +import com.velocitypowered.api.proxy.messages.ChannelIdentifier; import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.connection.VelocityConstants; import com.velocitypowered.proxy.connection.backend.VelocityServerConnection; @@ -298,14 +299,18 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { loginPluginMessages.add(packet); } } else { - PluginMessageEvent event = new PluginMessageEvent(player, player.getConnectedServer(), - server.getChannelRegistrar().getFromId(packet.getChannel()), packet.getData()); - server.getEventManager().fire(event) - .thenAcceptAsync(pme -> { - if (pme.getResult().isAllowed()) { - player.getConnectedServer().getMinecraftConnection().write(packet); - } - }, player.getConnectedServer().getMinecraftConnection().getChannel().eventLoop()); + ChannelIdentifier id = server.getChannelRegistrar().getFromId(packet.getChannel()); + if (id == null) { + player.getConnectedServer().getMinecraftConnection().write(packet); + } else { + PluginMessageEvent event = new PluginMessageEvent(player, player.getConnectedServer(), id, packet.getData()); + server.getEventManager().fire(event) + .thenAcceptAsync(pme -> { + if (pme.getResult().isAllowed()) { + player.getConnectedServer().getMinecraftConnection().write(packet); + } + }, player.getConnectedServer().getMinecraftConnection().getChannel().eventLoop()); + } } } From 037dceb599d57dd9fbf1c8bb9097d7d9f7bbdbbe Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sun, 16 Sep 2018 15:35:25 -0400 Subject: [PATCH 28/45] Fix potential race --- .../velocitypowered/proxy/server/ping/PingSessionHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/ping/PingSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/server/ping/PingSessionHandler.java index 4ed4dae44..60f2ea158 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/ping/PingSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/ping/PingSessionHandler.java @@ -62,6 +62,7 @@ public class PingSessionHandler implements MinecraftSessionHandler { @Override public void exception(Throwable throwable) { + completed = true; result.completeExceptionally(throwable); } } From e75ec71b32d061b44fceff76549f7158276c2847 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Mon, 17 Sep 2018 01:03:07 -0400 Subject: [PATCH 29/45] Improve native initialization logic This uses the double-check pattern as recommended in Effective Java. --- .../natives/util/NativeCodeLoader.java | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/native/src/main/java/com/velocitypowered/natives/util/NativeCodeLoader.java b/native/src/main/java/com/velocitypowered/natives/util/NativeCodeLoader.java index 2f07378c8..692df5375 100644 --- a/native/src/main/java/com/velocitypowered/natives/util/NativeCodeLoader.java +++ b/native/src/main/java/com/velocitypowered/natives/util/NativeCodeLoader.java @@ -8,7 +8,7 @@ import java.util.function.Supplier; public class NativeCodeLoader implements Supplier { private final List> variants; - private Variant selected; + private volatile Variant selected; public NativeCodeLoader(List> variants) { this.variants = ImmutableList.copyOf(variants); @@ -17,25 +17,32 @@ public class NativeCodeLoader implements Supplier { @Override public T get() { if (selected == null) { - selected = select(); + selected = tryLoad(); } return selected.object; } - private Variant select() { - for (Variant variant : variants) { - T got = variant.get(); - if (got == null) { - continue; + private Variant tryLoad() { + synchronized (this) { + if (selected != null) { + return selected; } - return variant; + + for (Variant variant : variants) { + T got = variant.get(); + if (got == null) { + continue; + } + selected = variant; + return selected; + } + throw new IllegalArgumentException("Can't find any suitable variants"); } - throw new IllegalArgumentException("Can't find any suitable variants"); } public String getLoadedVariant() { if (selected == null) { - selected = select(); + selected = tryLoad(); } return selected.name; } From fc48db62b564e2011a9a51ff3179ea0379907d56 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Mon, 17 Sep 2018 15:02:49 -0400 Subject: [PATCH 30/45] Improve native initialization logic, again --- .../natives/util/NativeCodeLoader.java | 61 ++++++++++--------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/native/src/main/java/com/velocitypowered/natives/util/NativeCodeLoader.java b/native/src/main/java/com/velocitypowered/natives/util/NativeCodeLoader.java index 692df5375..4b84516da 100644 --- a/native/src/main/java/com/velocitypowered/natives/util/NativeCodeLoader.java +++ b/native/src/main/java/com/velocitypowered/natives/util/NativeCodeLoader.java @@ -16,13 +16,14 @@ public class NativeCodeLoader implements Supplier { @Override public T get() { - if (selected == null) { - selected = tryLoad(); - } - return selected.object; + return tryLoad().object; } private Variant tryLoad() { + if (selected != null) { + return selected; + } + synchronized (this) { if (selected != null) { return selected; @@ -41,18 +42,15 @@ public class NativeCodeLoader implements Supplier { } public String getLoadedVariant() { - if (selected == null) { - selected = tryLoad(); - } - return selected.name; + return tryLoad().name; } static class Variant { - private boolean available; + private volatile boolean available; private final Runnable setup; private final String name; private final T object; - private boolean hasBeenSetup = false; + private volatile boolean hasBeenSetup = false; Variant(BooleanSupplier available, Runnable setup, String name, T object) { this.available = available.getAsBoolean(); @@ -61,27 +59,34 @@ public class NativeCodeLoader implements Supplier { this.object = object; } - private void setup() { - if (available && !hasBeenSetup) { - try { - setup.run(); - hasBeenSetup = true; - } catch (Exception e) { - available = false; + public T get() { + if (!available) { + return null; + } + + // Make sure setup happens only once + if (!hasBeenSetup) { + synchronized (this) { + // We change availability if need be below, may as well check it again here for sanity. + if (!available) { + return null; + } + + // Okay, now try the setup if we haven't done so yet. + if (!hasBeenSetup) { + try { + setup.run(); + hasBeenSetup = true; + return object; + } catch (Exception e) { + available = false; + return null; + } + } } } - } - public T get() { - if (!hasBeenSetup) { - setup(); - } - - if (available) { - return object; - } - - return null; + return object; } } From a60c55007a89a7cd7c0efa9592919e189ca555dd Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Mon, 17 Sep 2018 16:11:23 -0400 Subject: [PATCH 31/45] Remove LegacyChatColorUtils In most cases, you should only work with legacy text to deserialize or serialize it for backwards compatibility or user configurations only. --- .../api/util/LegacyChatColorUtils.java | 66 ------------------- .../api/util/LegacyChatColorUtilsTest.java | 62 ----------------- .../proxy/config/VelocityConfiguration.java | 2 - 3 files changed, 130 deletions(-) delete mode 100644 api/src/main/java/com/velocitypowered/api/util/LegacyChatColorUtils.java delete mode 100644 api/src/test/java/com/velocitypowered/api/util/LegacyChatColorUtilsTest.java diff --git a/api/src/main/java/com/velocitypowered/api/util/LegacyChatColorUtils.java b/api/src/main/java/com/velocitypowered/api/util/LegacyChatColorUtils.java deleted file mode 100644 index a21b97ffd..000000000 --- a/api/src/main/java/com/velocitypowered/api/util/LegacyChatColorUtils.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.velocitypowered.api.util; - -import com.google.common.base.Preconditions; -import org.checkerframework.checker.nullness.qual.NonNull; - -import java.util.regex.Pattern; - -/** - * LegacyChatColorUtils contains utilities for handling legacy Minecraft color codes. Generally, you should prefer - * JSON-based components, but for convenience Velocity provides a limited set of tools to handle Minecraft color codes. - */ -public class LegacyChatColorUtils { - private LegacyChatColorUtils() { - throw new AssertionError(); - } - - /** - * Represents the legacy Minecraft format character, the section symbol. - */ - public static final char FORMAT_CHAR = '\u00a7'; - - /** - * Translates a string with Minecraft color codes prefixed with a different character than the section symbol into - * a string that uses the section symbol. - * @param originalChar the char the color codes are prefixed by - * @param text the text to translate - * @return the translated text - */ - public static String translate(char originalChar, @NonNull String text) { - Preconditions.checkNotNull(text, "text"); - char[] textChars = text.toCharArray(); - int foundSectionIdx = -1; - for (int i = 0; i < textChars.length; i++) { - char textChar = textChars[i]; - if (textChar == originalChar) { - foundSectionIdx = i; - continue; - } - - if (foundSectionIdx >= 0) { - textChar = Character.toLowerCase(textChar); - if ((textChar >= 'a' && textChar <= 'f') || (textChar >= '0' && textChar <= '9') || - (textChar >= 'l' && textChar <= 'o' || textChar == 'r')) { - textChars[foundSectionIdx] = FORMAT_CHAR; - } - foundSectionIdx = -1; - } - } - return new String(textChars); - } - - /** - * A regex that matches all Minecraft color codes and removes them. - */ - private static final Pattern CHAT_COLOR_MATCHER = Pattern.compile("(?i)" + Character.toString(FORMAT_CHAR) + "[0-9A-FL-OR]"); - - /** - * Removes all Minecraft color codes from the string. - * @param text the text to remove color codes from - * @return a new String without Minecraft color codes - */ - public static String removeFormatting(@NonNull String text) { - Preconditions.checkNotNull(text, "text"); - return CHAT_COLOR_MATCHER.matcher(text).replaceAll(""); - } -} diff --git a/api/src/test/java/com/velocitypowered/api/util/LegacyChatColorUtilsTest.java b/api/src/test/java/com/velocitypowered/api/util/LegacyChatColorUtilsTest.java deleted file mode 100644 index b98b7027b..000000000 --- a/api/src/test/java/com/velocitypowered/api/util/LegacyChatColorUtilsTest.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.velocitypowered.api.util; - -import com.velocitypowered.api.util.LegacyChatColorUtils; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -class LegacyChatColorUtilsTest { - private static final String NON_FORMATTED = "Velocity"; - private static final String FORMATTED = "\u00a7cVelocity"; - private static final String FORMATTED_MULTIPLE = "\u00a7c\u00a7lVelocity"; - private static final String FORMATTED_MULTIPLE_VARIED = "\u00a7c\u00a7lVelo\u00a7a\u00a7mcity"; - private static final String INVALID = "\u00a7gVelocity"; - private static final String RAW_SECTION = "\u00a7"; - - @Test - void removeFormattingNonFormatted() { - assertEquals(NON_FORMATTED, LegacyChatColorUtils.removeFormatting(NON_FORMATTED)); - } - - @Test - void removeFormattingFormatted() { - assertEquals(NON_FORMATTED, LegacyChatColorUtils.removeFormatting(FORMATTED)); - } - - @Test - void removeFormattingFormattedMultiple() { - assertEquals(NON_FORMATTED, LegacyChatColorUtils.removeFormatting(FORMATTED_MULTIPLE)); - } - - @Test - void removeFormattingFormattedMultipleVaried() { - assertEquals(NON_FORMATTED, LegacyChatColorUtils.removeFormatting(FORMATTED_MULTIPLE_VARIED)); - } - - @Test - void removeFormattingInvalidFormat() { - assertEquals(INVALID, LegacyChatColorUtils.removeFormatting(INVALID)); - } - - @Test - void removeFormattingRawSection() { - assertEquals(RAW_SECTION, LegacyChatColorUtils.removeFormatting(RAW_SECTION)); - } - - @Test - void translate() { - assertEquals(FORMATTED, LegacyChatColorUtils.translate('&', "&cVelocity")); - } - - @Test - void translateMultiple() { - assertEquals(FORMATTED_MULTIPLE, LegacyChatColorUtils.translate('&', "&c&lVelocity")); - assertEquals(FORMATTED_MULTIPLE_VARIED, LegacyChatColorUtils.translate('&', "&c&lVelo&a&mcity")); - } - - @Test - void translateDifferentChar() { - assertEquals(FORMATTED, LegacyChatColorUtils.translate('$', "$cVelocity")); - assertEquals(FORMATTED_MULTIPLE_VARIED, LegacyChatColorUtils.translate('$', "$c$lVelo$a$mcity")); - } -} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java b/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java index feb076dbb..c2ada433c 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java @@ -5,8 +5,6 @@ import com.google.common.collect.ImmutableMap; import com.moandjiezana.toml.Toml; import com.velocitypowered.api.util.Favicon; import com.velocitypowered.proxy.util.AddressUtil; -import com.velocitypowered.api.util.LegacyChatColorUtils; -import io.netty.buffer.ByteBufUtil; import net.kyori.text.Component; import net.kyori.text.serializer.ComponentSerializers; From f973ded4eeb867e6a125c13d332943b1eeea31bb Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Mon, 17 Sep 2018 16:18:47 -0400 Subject: [PATCH 32/45] Tighten identifier checks since NuVotifier fixed this --- .../api/proxy/messages/MinecraftChannelIdentifier.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/com/velocitypowered/api/proxy/messages/MinecraftChannelIdentifier.java b/api/src/main/java/com/velocitypowered/api/proxy/messages/MinecraftChannelIdentifier.java index b8f689324..1355ed239 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/messages/MinecraftChannelIdentifier.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/messages/MinecraftChannelIdentifier.java @@ -10,7 +10,7 @@ import java.util.regex.Pattern; * Represents a Minecraft 1.13+ channel identifier. This class is immutable and safe for multi-threaded use. */ public final class MinecraftChannelIdentifier implements ChannelIdentifier { - private static final Pattern VALID_IDENTIFIER_REGEX = Pattern.compile("[a-z0-9\\-_]+", Pattern.CASE_INSENSITIVE); + private static final Pattern VALID_IDENTIFIER_REGEX = Pattern.compile("[a-z0-9\\-_]+"); private final String namespace; private final String name; From 44b1b82b09ae7b0fa3622d445f56e313be365e1e Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Tue, 18 Sep 2018 16:40:51 -0400 Subject: [PATCH 33/45] Try to avoid locking, use an actual concurrent data structure --- .../proxy/server/ServerMap.java | 41 ++++------------- .../server/VelocityRegisteredServer.java | 45 +++++-------------- 2 files changed, 19 insertions(+), 67 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/ServerMap.java b/proxy/src/main/java/com/velocitypowered/proxy/server/ServerMap.java index 30835df3e..357c97e95 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/ServerMap.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/ServerMap.java @@ -7,13 +7,10 @@ import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.proxy.VelocityServer; import java.util.*; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; public class ServerMap { private final VelocityServer server; private final Map servers = new HashMap<>(); - private final ReadWriteLock lock = new ReentrantReadWriteLock(); public ServerMap(VelocityServer server) { this.server = server; @@ -22,47 +19,27 @@ public class ServerMap { public Optional getServer(String name) { Preconditions.checkNotNull(name, "server"); String lowerName = name.toLowerCase(Locale.US); - lock.readLock().lock(); - try { - return Optional.ofNullable(servers.get(lowerName)); - } finally { - lock.readLock().unlock(); - } + return Optional.ofNullable(servers.get(lowerName)); } public Collection getAllServers() { - lock.readLock().lock(); - try { - return ImmutableList.copyOf(servers.values()); - } finally { - lock.readLock().unlock(); - } + return ImmutableList.copyOf(servers.values()); } public RegisteredServer register(ServerInfo serverInfo) { Preconditions.checkNotNull(serverInfo, "serverInfo"); String lowerName = serverInfo.getName().toLowerCase(Locale.US); - lock.writeLock().lock(); - try { - VelocityRegisteredServer rs = new VelocityRegisteredServer(server, serverInfo); - Preconditions.checkArgument(servers.putIfAbsent(lowerName, rs) == null, "Server with name %s already registered", serverInfo.getName()); - return rs; - } finally { - lock.writeLock().unlock(); - } + VelocityRegisteredServer rs = new VelocityRegisteredServer(server, serverInfo); + Preconditions.checkArgument(servers.putIfAbsent(lowerName, rs) == null, "Server with name %s already registered", serverInfo.getName()); + return rs; } public void unregister(ServerInfo serverInfo) { Preconditions.checkNotNull(serverInfo, "serverInfo"); String lowerName = serverInfo.getName().toLowerCase(Locale.US); - lock.writeLock().lock(); - try { - RegisteredServer rs = servers.get(lowerName); - Preconditions.checkArgument(rs != null, "Server with name %s is not registered!", serverInfo.getName()); - Preconditions.checkArgument(rs.getServerInfo().equals(serverInfo), "Trying to remove server %s with differing information", serverInfo.getName()); - servers.remove(lowerName); - } finally { - lock.writeLock().unlock(); - } + RegisteredServer rs = servers.get(lowerName); + Preconditions.checkArgument(rs != null, "Server with name %s is not registered!", serverInfo.getName()); + Preconditions.checkArgument(rs.getServerInfo().equals(serverInfo), "Trying to remove server %s with differing information", serverInfo.getName()); + Preconditions.checkState(servers.remove(lowerName, rs), "Server with name %s replaced whilst unregistering", serverInfo.getName()); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java b/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java index 18dfef0d0..b937fc926 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java @@ -25,6 +25,7 @@ import io.netty.handler.timeout.ReadTimeoutHandler; import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -36,8 +37,7 @@ import static com.velocitypowered.proxy.network.Connections.MINECRAFT_ENCODER; public class VelocityRegisteredServer implements RegisteredServer { private final VelocityServer server; private final ServerInfo serverInfo; - private final Set players = new HashSet<>(); - private final ReadWriteLock playersLock = new ReentrantReadWriteLock(); + private final Set players = ConcurrentHashMap.newKeySet(); public VelocityRegisteredServer(VelocityServer server, ServerInfo serverInfo) { this.server = server; @@ -51,12 +51,7 @@ public class VelocityRegisteredServer implements RegisteredServer { @Override public Collection getPlayersConnected() { - playersLock.readLock().lock(); - try { - return ImmutableList.copyOf(players); - } finally { - playersLock.readLock().unlock(); - } + return ImmutableList.copyOf(players); } @Override @@ -94,43 +89,23 @@ public class VelocityRegisteredServer implements RegisteredServer { } public void addPlayer(ConnectedPlayer player) { - playersLock.writeLock().lock(); - try { - players.add(player); - } finally { - playersLock.writeLock().unlock(); - } + players.add(player); } public void removePlayer(ConnectedPlayer player) { - playersLock.writeLock().lock(); - try { - players.remove(player); - } finally { - playersLock.writeLock().unlock(); - } + players.remove(player); } @Override public boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data) { - ServerConnection backendConnection = null; - playersLock.readLock().lock(); - try { - for (ConnectedPlayer player : players) { - if (player.getConnectedServer() != null && player.getConnectedServer().getServerInfo().equals(serverInfo)) { - backendConnection = player.getConnectedServer(); - break; - } + for (ConnectedPlayer player : players) { + if (player.getConnectedServer() != null && player.getConnectedServer().getServerInfo().equals(serverInfo)) { + ServerConnection connection = player.getConnectedServer(); + return connection.sendPluginMessage(identifier, data); } - - if (backendConnection == null) { - return false; - } - } finally { - playersLock.readLock().unlock(); } - return backendConnection.sendPluginMessage(identifier, data); + return false; } @Override From 2bfb7061ee746a85c1f824721732079902fd9270 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Tue, 18 Sep 2018 16:48:21 -0400 Subject: [PATCH 34/45] Turn StatusRequest into a singleton. --- .../velocitypowered/proxy/protocol/StateRegistry.java | 2 +- .../proxy/protocol/packet/StatusRequest.java | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java index 91fab4eb4..f343adae4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -23,7 +23,7 @@ public enum StateRegistry { }, STATUS { { - SERVERBOUND.register(StatusRequest.class, StatusRequest::new, + SERVERBOUND.register(StatusRequest.class, () -> StatusRequest.INSTANCE, genericMappings(0x00)); SERVERBOUND.register(StatusPing.class, StatusPing::new, genericMappings(0x01)); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusRequest.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusRequest.java index c53276e5a..ff9897c69 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusRequest.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusRequest.java @@ -5,6 +5,12 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import io.netty.buffer.ByteBuf; public class StatusRequest implements MinecraftPacket { + public static final StatusRequest INSTANCE = new StatusRequest(); + + private StatusRequest() { + + } + @Override public void decode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { @@ -14,4 +20,9 @@ public class StatusRequest implements MinecraftPacket { public void encode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { } + + @Override + public String toString() { + return "StatusRequest"; + } } From 508ba3569731e86bca30bc0af608ef2d8d6c7404 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Tue, 18 Sep 2018 16:48:52 -0400 Subject: [PATCH 35/45] Exclude plugins from Git. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index fd8f6bff5..aa52285df 100644 --- a/.gitignore +++ b/.gitignore @@ -135,3 +135,4 @@ logs/ server-icon.png /bin/ run/ +plugins/ \ No newline at end of file From 717c2afeb33da124f644b6afeb6744cc2e2c8726 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Tue, 18 Sep 2018 16:50:33 -0400 Subject: [PATCH 36/45] Update for changes in master. --- .../velocitypowered/proxy/server/ping/PingSessionHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/ping/PingSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/server/ping/PingSessionHandler.java index 60f2ea158..0bce28b74 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/ping/PingSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/ping/PingSessionHandler.java @@ -38,7 +38,7 @@ public class PingSessionHandler implements MinecraftSessionHandler { connection.write(handshake); connection.setState(StateRegistry.STATUS); - connection.write(new StatusRequest()); + connection.write(StatusRequest.INSTANCE); } @Override From c38b73863a1a5306454bc7b7a67f5801079a792f Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Tue, 18 Sep 2018 16:59:13 -0400 Subject: [PATCH 37/45] Fix more scheduler issues --- .../proxy/scheduler/VelocityScheduler.java | 68 ++++--------------- 1 file changed, 12 insertions(+), 56 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java b/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java index 6e10807e3..6f61cea06 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java @@ -91,62 +91,9 @@ public class VelocityScheduler implements Scheduler { @Override public ScheduledTask schedule() { - if (delay == 0 && repeat == 0) { - // A special purpose, simplified implementation - VelocityImmediatelyScheduledTask task = new VelocityImmediatelyScheduledTask(plugin, runnable); - tasksByPlugin.put(plugin, task); - taskService.execute(task); - return task; - } else { - VelocityTask task = new VelocityTask(plugin, runnable, delay, repeat); - tasksByPlugin.put(plugin, task); - return task; - } - } - } - - private class VelocityImmediatelyScheduledTask implements ScheduledTask, Runnable { - private final Object plugin; - private final Runnable runnable; - private final AtomicReference status; - private Thread taskThread; - - private VelocityImmediatelyScheduledTask(Object plugin, Runnable runnable) { - this.plugin = plugin; - this.runnable = runnable; - this.status = new AtomicReference<>(TaskStatus.SCHEDULED); - } - - @Override - public Object plugin() { - return plugin; - } - - @Override - public TaskStatus status() { - return status.get(); - } - - @Override - public void cancel() { - if (status.compareAndSet(TaskStatus.SCHEDULED, TaskStatus.CANCELLED)) { - if (taskThread != null) { - taskThread.interrupt(); - } - } - } - - @Override - public void run() { - taskThread = Thread.currentThread(); - try { - runnable.run(); - } catch (Exception e) { - Log.logger.error("Exception in task {} by plugin {}", runnable, plugin); - } - status.compareAndSet(TaskStatus.SCHEDULED, TaskStatus.FINISHED); - taskThread = null; - tasksByPlugin.remove(plugin, this); + VelocityTask task = new VelocityTask(plugin, runnable, delay, repeat); + tasksByPlugin.put(plugin, task); + return task; } } @@ -154,6 +101,7 @@ public class VelocityScheduler implements Scheduler { private final Object plugin; private final Runnable runnable; private ScheduledFuture future; + private volatile Thread currentTaskThread; private VelocityTask(Object plugin, Runnable runnable, long delay, long repeat) { this.plugin = plugin; @@ -191,6 +139,12 @@ public class VelocityScheduler implements Scheduler { public void cancel() { if (future != null) { future.cancel(false); + + Thread cur = currentTaskThread; + if (cur != null) { + cur.interrupt(); + } + onFinish(); } } @@ -198,6 +152,7 @@ public class VelocityScheduler implements Scheduler { @Override public void run() { taskService.execute(() -> { + currentTaskThread = Thread.currentThread(); try { runnable.run(); } catch (Exception e) { @@ -208,6 +163,7 @@ public class VelocityScheduler implements Scheduler { Log.logger.error("Exception in task {} by plugin {}", runnable, plugin); } } + currentTaskThread = null; }); } From d796f079f075567b41506ab079c3dbe7820c3b8e Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Tue, 18 Sep 2018 17:01:26 -0400 Subject: [PATCH 38/45] I forgot this. --- .../main/java/com/velocitypowered/proxy/server/ServerMap.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/ServerMap.java b/proxy/src/main/java/com/velocitypowered/proxy/server/ServerMap.java index 357c97e95..247b5ebfe 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/ServerMap.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/ServerMap.java @@ -7,10 +7,11 @@ import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.proxy.VelocityServer; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; public class ServerMap { private final VelocityServer server; - private final Map servers = new HashMap<>(); + private final Map servers = new ConcurrentHashMap<>(); public ServerMap(VelocityServer server) { this.server = server; From 9016162a49ee266f045bd01425e0fb5db050aae2 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Tue, 18 Sep 2018 17:24:28 -0400 Subject: [PATCH 39/45] Optimize and clarify GS4 query handler. --- .../proxy/protocol/netty/GS4QueryHandler.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/GS4QueryHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/GS4QueryHandler.java index df093d78d..2628bc445 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/GS4QueryHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/GS4QueryHandler.java @@ -101,9 +101,6 @@ public class GS4QueryHandler extends SimpleChannelInboundHandler queryResponse.writeByte(QUERY_TYPE_STAT); queryResponse.writeInt(sessionId); - // Fetch information - Collection players = server.getAllPlayers(); - // Start writing the response ResponseWriter responseWriter = new ResponseWriter(queryResponse, queryMessage.readableBytes() == 0); responseWriter.write("hostname", ComponentSerializers.PLAIN.serialize(server.getConfiguration().getMotdComponent())); @@ -114,12 +111,14 @@ public class GS4QueryHandler extends SimpleChannelInboundHandler responseWriter.write("plugins", ""); responseWriter.write("map", "Velocity"); - responseWriter.write("numplayers", players.size()); + responseWriter.write("numplayers", server.getPlayerCount()); responseWriter.write("maxplayers", server.getConfiguration().getShowMaxPlayers()); responseWriter.write("hostport", server.getConfiguration().getBind().getPort()); responseWriter.write("hostip", server.getConfiguration().getBind().getHostString()); - responseWriter.writePlayers(players); + if (!responseWriter.isBasic) { + responseWriter.writePlayers(server.getAllPlayers()); + } break; } @@ -132,6 +131,8 @@ public class GS4QueryHandler extends SimpleChannelInboundHandler ctx.writeAndFlush(responsePacket); } catch (Exception e) { logger.warn("Error while trying to handle a query packet from {}", msg.sender(), e); + // NB: Only need to explicitly release upon exception, writing the response out will decrement the reference + // count. responsePacket.release(); } } From 50c27066e2d823460e6d32fa83b47d91206d64e2 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Wed, 19 Sep 2018 14:56:49 -0400 Subject: [PATCH 40/45] Import cleanup --- .../plugin/ap/PluginAnnotationProcessor.java | 3 ++- .../api/event/connection/PreLoginEvent.java | 5 ++-- .../event/player/GameProfileRequestEvent.java | 5 ++-- .../event/player/KickedFromServerEvent.java | 1 - .../player/PlayerSettingsChangedEvent.java | 2 +- .../event/player/ServerPreConnectEvent.java | 1 - .../api/plugin/meta/PluginDependency.java | 1 - .../api/proxy/ConnectionRequestBuilder.java | 2 -- .../com/velocitypowered/api/proxy/Player.java | 3 +-- .../api/proxy/ProxyServer.java | 4 ++-- .../velocitypowered/natives/util/Natives.java | 2 -- .../compression/VelocityCompressorTest.java | 1 - .../velocitypowered/proxy/VelocityServer.java | 16 ++++++------- .../proxy/command/VelocityCommandManager.java | 3 +-- .../proxy/config/AnnotatedConfig.java | 11 ++++----- .../proxy/config/VelocityConfiguration.java | 8 ++----- .../proxy/connection/MinecraftConnection.java | 12 ++-------- .../backend/BackendPlaySessionHandler.java | 2 +- .../backend/LoginSessionHandler.java | 4 ++-- .../backend/VelocityServerConnection.java | 23 ++++++++----------- .../client/ClientPlaySessionHandler.java | 2 +- .../client/ClientSettingsWrapper.java | 1 + .../connection/client/ConnectedPlayer.java | 18 +++++---------- .../client/HandshakeSessionHandler.java | 2 +- .../client/InitialConnectSessionHandler.java | 2 +- .../client/LoginSessionHandler.java | 11 ++++----- .../client/StatusSessionHandler.java | 6 ++--- .../proxy/console/VelocityConsole.java | 4 +++- .../messages/VelocityChannelRegistrar.java | 5 +++- .../proxy/network/ConnectionManager.java | 14 ++--------- .../proxy/network/http/NettyHttpClient.java | 2 +- .../proxy/plugin/VelocityEventManager.java | 14 ++++++++--- .../proxy/plugin/VelocityPluginManager.java | 2 +- .../proxy/plugin/loader/JavaPluginLoader.java | 4 +++- .../loader/java/VelocityPluginModule.java | 1 - .../proxy/protocol/StateRegistry.java | 2 +- .../netty/MinecraftCompressDecoder.java | 2 +- .../netty/MinecraftCompressEncoder.java | 2 +- .../protocol/netty/MinecraftDecoder.java | 5 +++- .../netty/MinecraftVarintLengthEncoder.java | 1 - .../proxy/protocol/packet/Chat.java | 2 +- .../proxy/protocol/packet/Disconnect.java | 2 +- .../proxy/protocol/packet/Handshake.java | 2 +- .../protocol/packet/HeaderAndFooter.java | 4 ++-- .../proxy/protocol/packet/KeepAlive.java | 2 +- .../proxy/protocol/packet/ServerLogin.java | 2 +- .../proxy/protocol/packet/StatusRequest.java | 2 +- .../proxy/protocol/packet/StatusResponse.java | 2 +- .../protocol/util/PluginMessageUtil.java | 1 - .../proxy/scheduler/VelocityScheduler.java | 1 - .../proxy/server/ServerMap.java | 5 +++- .../server/VelocityRegisteredServer.java | 7 ++---- .../concurrency/RecordingThreadFactory.java | 1 - .../proxy/protocol/PacketRegistryTest.java | 4 +--- .../scheduler/VelocitySchedulerTest.java | 2 +- .../proxy/util/RatelimiterTest.java | 3 ++- .../proxy/util/ServerMapTest.java | 3 ++- 57 files changed, 111 insertions(+), 143 deletions(-) diff --git a/api/src/ap/java/com/velocitypowered/api/plugin/ap/PluginAnnotationProcessor.java b/api/src/ap/java/com/velocitypowered/api/plugin/ap/PluginAnnotationProcessor.java index a00f9c7d3..6a8310c72 100644 --- a/api/src/ap/java/com/velocitypowered/api/plugin/ap/PluginAnnotationProcessor.java +++ b/api/src/ap/java/com/velocitypowered/api/plugin/ap/PluginAnnotationProcessor.java @@ -19,7 +19,8 @@ import javax.tools.StandardLocation; import java.io.BufferedWriter; import java.io.IOException; import java.io.Writer; -import java.util.*; +import java.util.Objects; +import java.util.Set; @SupportedAnnotationTypes({"com.velocitypowered.api.plugin.Plugin"}) public class PluginAnnotationProcessor extends AbstractProcessor { diff --git a/api/src/main/java/com/velocitypowered/api/event/connection/PreLoginEvent.java b/api/src/main/java/com/velocitypowered/api/event/connection/PreLoginEvent.java index 04fdc7622..d5e817f49 100644 --- a/api/src/main/java/com/velocitypowered/api/event/connection/PreLoginEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/connection/PreLoginEvent.java @@ -3,14 +3,13 @@ package com.velocitypowered.api.event.connection; import com.google.common.base.Preconditions; import com.velocitypowered.api.event.ResultedEvent; import com.velocitypowered.api.proxy.InboundConnection; -import java.util.Optional; - import net.kyori.text.Component; import net.kyori.text.serializer.ComponentSerializers; - import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import java.util.Optional; + /** * This event is fired when a player has initiated a connection with the proxy but before the proxy authenticates the * player with Mojang or before the player's proxy connection is fully established (for offline mode). diff --git a/api/src/main/java/com/velocitypowered/api/event/player/GameProfileRequestEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/GameProfileRequestEvent.java index 2a02d0a18..ab46c37c1 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/GameProfileRequestEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/GameProfileRequestEvent.java @@ -1,10 +1,9 @@ package com.velocitypowered.api.event.player; -import com.velocitypowered.api.proxy.InboundConnection; -import org.checkerframework.checker.nullness.qual.Nullable; - import com.google.common.base.Preconditions; +import com.velocitypowered.api.proxy.InboundConnection; import com.velocitypowered.api.util.GameProfile; +import org.checkerframework.checker.nullness.qual.Nullable; /** * This event is fired after the {@link com.velocitypowered.api.event.connection.PreLoginEvent} in order to set up the diff --git a/api/src/main/java/com/velocitypowered/api/event/player/KickedFromServerEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/KickedFromServerEvent.java index 86bce5e66..bfdf296e6 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/KickedFromServerEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/KickedFromServerEvent.java @@ -4,7 +4,6 @@ import com.google.common.base.Preconditions; import com.velocitypowered.api.event.ResultedEvent; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.server.RegisteredServer; -import com.velocitypowered.api.proxy.server.ServerInfo; import net.kyori.text.Component; import org.checkerframework.checker.nullness.qual.NonNull; diff --git a/api/src/main/java/com/velocitypowered/api/event/player/PlayerSettingsChangedEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/PlayerSettingsChangedEvent.java index a657543ad..b59c643ff 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/PlayerSettingsChangedEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/PlayerSettingsChangedEvent.java @@ -1,8 +1,8 @@ package com.velocitypowered.api.event.player; import com.google.common.base.Preconditions; -import com.velocitypowered.api.proxy.player.PlayerSettings; import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.proxy.player.PlayerSettings; public class PlayerSettingsChangedEvent { private final Player player; diff --git a/api/src/main/java/com/velocitypowered/api/event/player/ServerPreConnectEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/ServerPreConnectEvent.java index 8aa142ddd..f80d3cb33 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/ServerPreConnectEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/ServerPreConnectEvent.java @@ -4,7 +4,6 @@ import com.google.common.base.Preconditions; import com.velocitypowered.api.event.ResultedEvent; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.server.RegisteredServer; -import com.velocitypowered.api.proxy.server.ServerInfo; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; diff --git a/api/src/main/java/com/velocitypowered/api/plugin/meta/PluginDependency.java b/api/src/main/java/com/velocitypowered/api/plugin/meta/PluginDependency.java index f63b87c5c..2229d6ed3 100644 --- a/api/src/main/java/com/velocitypowered/api/plugin/meta/PluginDependency.java +++ b/api/src/main/java/com/velocitypowered/api/plugin/meta/PluginDependency.java @@ -1,7 +1,6 @@ package com.velocitypowered.api.plugin.meta; import javax.annotation.Nullable; - import java.util.Objects; import java.util.Optional; diff --git a/api/src/main/java/com/velocitypowered/api/proxy/ConnectionRequestBuilder.java b/api/src/main/java/com/velocitypowered/api/proxy/ConnectionRequestBuilder.java index 17c9173f3..d7369a15c 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/ConnectionRequestBuilder.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/ConnectionRequestBuilder.java @@ -1,9 +1,7 @@ package com.velocitypowered.api.proxy; import com.velocitypowered.api.proxy.server.RegisteredServer; -import com.velocitypowered.api.proxy.server.ServerInfo; import net.kyori.text.Component; -import org.checkerframework.checker.nullness.qual.NonNull; import java.util.Optional; import java.util.concurrent.CompletableFuture; diff --git a/api/src/main/java/com/velocitypowered/api/proxy/Player.java b/api/src/main/java/com/velocitypowered/api/proxy/Player.java index 83c05a4ae..0bdc9b607 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/Player.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/Player.java @@ -1,11 +1,10 @@ package com.velocitypowered.api.proxy; import com.velocitypowered.api.command.CommandSource; -import com.velocitypowered.api.proxy.player.PlayerSettings; import com.velocitypowered.api.proxy.messages.ChannelMessageSink; import com.velocitypowered.api.proxy.messages.ChannelMessageSource; +import com.velocitypowered.api.proxy.player.PlayerSettings; import com.velocitypowered.api.proxy.server.RegisteredServer; -import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.api.util.MessagePosition; import net.kyori.text.Component; import org.checkerframework.checker.nullness.qual.NonNull; diff --git a/api/src/main/java/com/velocitypowered/api/proxy/ProxyServer.java b/api/src/main/java/com/velocitypowered/api/proxy/ProxyServer.java index 553e88c10..c6c75df8a 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/ProxyServer.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/ProxyServer.java @@ -1,13 +1,13 @@ package com.velocitypowered.api.proxy; -import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.command.CommandManager; +import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.event.EventManager; import com.velocitypowered.api.plugin.PluginManager; import com.velocitypowered.api.proxy.messages.ChannelRegistrar; import com.velocitypowered.api.proxy.server.RegisteredServer; -import com.velocitypowered.api.scheduler.Scheduler; import com.velocitypowered.api.proxy.server.ServerInfo; +import com.velocitypowered.api.scheduler.Scheduler; import java.net.InetSocketAddress; import java.util.Collection; diff --git a/native/src/main/java/com/velocitypowered/natives/util/Natives.java b/native/src/main/java/com/velocitypowered/natives/util/Natives.java index 9c135843d..5c22ae752 100644 --- a/native/src/main/java/com/velocitypowered/natives/util/Natives.java +++ b/native/src/main/java/com/velocitypowered/natives/util/Natives.java @@ -3,10 +3,8 @@ package com.velocitypowered.natives.util; import com.google.common.collect.ImmutableList; import com.velocitypowered.natives.compression.JavaVelocityCompressor; import com.velocitypowered.natives.compression.NativeVelocityCompressor; -import com.velocitypowered.natives.compression.VelocityCompressor; import com.velocitypowered.natives.compression.VelocityCompressorFactory; import com.velocitypowered.natives.encryption.JavaVelocityCipher; -import com.velocitypowered.natives.encryption.NativeVelocityCipher; import com.velocitypowered.natives.encryption.VelocityCipherFactory; import java.io.IOException; diff --git a/native/src/test/java/com/velocitypowered/natives/compression/VelocityCompressorTest.java b/native/src/test/java/com/velocitypowered/natives/compression/VelocityCompressorTest.java index 93136b8df..363c80442 100644 --- a/native/src/test/java/com/velocitypowered/natives/compression/VelocityCompressorTest.java +++ b/native/src/test/java/com/velocitypowered/natives/compression/VelocityCompressorTest.java @@ -9,7 +9,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledOnOs; import java.util.Random; -import java.util.function.Supplier; import java.util.zip.DataFormatException; import java.util.zip.Deflater; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java index b9711f915..7eaf8eaf3 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java @@ -8,30 +8,30 @@ import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.event.EventManager; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; import com.velocitypowered.api.event.proxy.ProxyShutdownEvent; +import com.velocitypowered.api.plugin.PluginManager; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.server.RegisteredServer; -import com.velocitypowered.api.util.Favicon; -import com.velocitypowered.api.plugin.PluginManager; import com.velocitypowered.api.proxy.server.ServerInfo; -import com.velocitypowered.proxy.network.ConnectionManager; +import com.velocitypowered.api.util.Favicon; import com.velocitypowered.proxy.command.ServerCommand; import com.velocitypowered.proxy.command.ShutdownCommand; import com.velocitypowered.proxy.command.VelocityCommand; -import com.velocitypowered.proxy.config.VelocityConfiguration; -import com.velocitypowered.proxy.connection.client.ConnectedPlayer; -import com.velocitypowered.proxy.network.http.NettyHttpClient; import com.velocitypowered.proxy.command.VelocityCommandManager; import com.velocitypowered.proxy.config.AnnotatedConfig; +import com.velocitypowered.proxy.config.VelocityConfiguration; +import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.messages.VelocityChannelRegistrar; +import com.velocitypowered.proxy.network.ConnectionManager; +import com.velocitypowered.proxy.network.http.NettyHttpClient; import com.velocitypowered.proxy.plugin.VelocityEventManager; -import com.velocitypowered.proxy.protocol.util.FaviconSerializer; import com.velocitypowered.proxy.plugin.VelocityPluginManager; +import com.velocitypowered.proxy.protocol.util.FaviconSerializer; import com.velocitypowered.proxy.scheduler.VelocityScheduler; +import com.velocitypowered.proxy.server.ServerMap; import com.velocitypowered.proxy.util.AddressUtil; import com.velocitypowered.proxy.util.EncryptionUtils; import com.velocitypowered.proxy.util.Ratelimiter; -import com.velocitypowered.proxy.server.ServerMap; import io.netty.bootstrap.Bootstrap; import net.kyori.text.Component; import net.kyori.text.TextComponent; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java index 38c3759ea..7793bf075 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java @@ -1,10 +1,9 @@ package com.velocitypowered.proxy.command; import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; import com.velocitypowered.api.command.Command; -import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.command.CommandManager; +import com.velocitypowered.api.command.CommandSource; import java.util.*; import java.util.stream.Collectors; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/config/AnnotatedConfig.java b/proxy/src/main/java/com/velocitypowered/proxy/config/AnnotatedConfig.java index 32f9a4880..99a417846 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/config/AnnotatedConfig.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/config/AnnotatedConfig.java @@ -1,5 +1,8 @@ package com.velocitypowered.proxy.config; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + import java.io.File; import java.io.IOException; import java.lang.annotation.ElementType; @@ -8,18 +11,12 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Field; import java.nio.charset.StandardCharsets; -import java.nio.file.AtomicMoveNotSupportedException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.nio.file.StandardOpenOption; +import java.nio.file.*; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; /** * Only for simple configs diff --git a/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java b/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java index c2ada433c..303dbcd3f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java @@ -7,6 +7,7 @@ import com.velocitypowered.api.util.Favicon; import com.velocitypowered.proxy.util.AddressUtil; import net.kyori.text.Component; import net.kyori.text.serializer.ComponentSerializers; +import org.apache.logging.log4j.Logger; import java.io.IOException; import java.io.Reader; @@ -15,12 +16,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; -import org.apache.logging.log4j.Logger; +import java.util.*; public class VelocityConfiguration extends AnnotatedConfig { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java index 0f6844304..6f57fd2ba 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -2,13 +2,13 @@ package com.velocitypowered.proxy.connection; import com.google.common.base.Preconditions; import com.velocitypowered.natives.compression.VelocityCompressor; +import com.velocitypowered.natives.encryption.VelocityCipher; import com.velocitypowered.natives.encryption.VelocityCipherFactory; import com.velocitypowered.natives.util.Natives; import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.StateRegistry; -import com.velocitypowered.natives.encryption.VelocityCipher; import com.velocitypowered.proxy.protocol.netty.*; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; @@ -21,17 +21,9 @@ import org.apache.logging.log4j.Logger; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; - import java.security.GeneralSecurityException; -import static com.velocitypowered.proxy.network.Connections.CIPHER_DECODER; -import static com.velocitypowered.proxy.network.Connections.CIPHER_ENCODER; -import static com.velocitypowered.proxy.network.Connections.COMPRESSION_DECODER; -import static com.velocitypowered.proxy.network.Connections.COMPRESSION_ENCODER; -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.MINECRAFT_DECODER; -import static com.velocitypowered.proxy.network.Connections.MINECRAFT_ENCODER; +import static com.velocitypowered.proxy.network.Connections.*; /** * A utility class to make working with the pipeline a little less painful and transparently handles certain Minecraft diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java index f0d23d362..fea65c6a9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java @@ -4,13 +4,13 @@ import com.velocitypowered.api.event.connection.PluginMessageEvent; import com.velocitypowered.api.event.player.ServerConnectedEvent; import com.velocitypowered.api.proxy.messages.ChannelIdentifier; import com.velocitypowered.proxy.VelocityServer; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.connection.VelocityConstants; import com.velocitypowered.proxy.connection.client.ClientPlaySessionHandler; import com.velocitypowered.proxy.connection.util.ConnectionMessages; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.packet.*; -import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.protocol.util.PluginMessageUtil; import io.netty.buffer.ByteBuf; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java index 1a7f5e2df..5fb5341b2 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java @@ -1,18 +1,18 @@ package com.velocitypowered.proxy.connection.backend; import com.velocitypowered.api.proxy.ConnectionRequestBuilder; +import com.velocitypowered.api.util.GameProfile; import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.config.PlayerInfoForwarding; import com.velocitypowered.proxy.config.VelocityConfiguration; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.connection.VelocityConstants; import com.velocitypowered.proxy.connection.client.ClientPlaySessionHandler; import com.velocitypowered.proxy.connection.util.ConnectionRequestResults; -import com.velocitypowered.api.util.GameProfile; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.packet.*; -import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import net.kyori.text.TextComponent; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java index 87f55b6e9..80210e33a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java @@ -4,10 +4,14 @@ import com.google.common.base.Preconditions; 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.RegisteredServer; +import com.velocitypowered.api.proxy.server.ServerInfo; +import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.config.PlayerInfoForwarding; +import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation; +import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.protocol.ProtocolConstants; +import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder; import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder; import com.velocitypowered.proxy.protocol.netty.MinecraftVarintFrameDecoder; @@ -15,13 +19,11 @@ import com.velocitypowered.proxy.protocol.netty.MinecraftVarintLengthEncoder; import com.velocitypowered.proxy.protocol.packet.Handshake; import com.velocitypowered.proxy.protocol.packet.PluginMessage; import com.velocitypowered.proxy.protocol.packet.ServerLogin; -import com.velocitypowered.proxy.connection.MinecraftConnection; -import com.velocitypowered.proxy.protocol.StateRegistry; -import com.velocitypowered.api.proxy.server.ServerInfo; -import com.velocitypowered.proxy.VelocityServer; -import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.server.VelocityRegisteredServer; -import io.netty.channel.*; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelInitializer; import io.netty.handler.timeout.ReadTimeoutHandler; import io.netty.util.AttributeKey; @@ -29,12 +31,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import static com.velocitypowered.proxy.VelocityServer.GSON; -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; -import static com.velocitypowered.proxy.network.Connections.MINECRAFT_DECODER; -import static com.velocitypowered.proxy.network.Connections.MINECRAFT_ENCODER; -import static com.velocitypowered.proxy.network.Connections.READ_TIMEOUT; +import static com.velocitypowered.proxy.network.Connections.*; public class VelocityServerConnection implements MinecraftConnectionAssociation, ServerConnection { static final AttributeKey> CONNECTION_NOTIFIER = diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index 836481fba..91d2d64ac 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -4,12 +4,12 @@ import com.velocitypowered.api.event.connection.DisconnectEvent; import com.velocitypowered.api.event.connection.PluginMessageEvent; import com.velocitypowered.api.proxy.messages.ChannelIdentifier; import com.velocitypowered.proxy.VelocityServer; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.connection.VelocityConstants; import com.velocitypowered.proxy.connection.backend.VelocityServerConnection; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.packet.*; -import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.protocol.util.PluginMessageUtil; import com.velocitypowered.proxy.util.ThrowableUtils; import io.netty.buffer.ByteBuf; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientSettingsWrapper.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientSettingsWrapper.java index 4977c5df9..235915f24 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientSettingsWrapper.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientSettingsWrapper.java @@ -3,6 +3,7 @@ package com.velocitypowered.proxy.connection.client; import com.velocitypowered.api.proxy.player.PlayerSettings; import com.velocitypowered.api.proxy.player.SkinParts; import com.velocitypowered.proxy.protocol.packet.ClientSettings; + import java.util.Locale; public class ClientSettingsWrapper implements PlayerSettings { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java index 5cfe49ac4..032f7c8fa 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java @@ -7,30 +7,24 @@ import com.velocitypowered.api.event.player.PlayerSettingsChangedEvent; import com.velocitypowered.api.event.player.ServerPreConnectEvent; import com.velocitypowered.api.permission.PermissionFunction; import com.velocitypowered.api.permission.PermissionProvider; -import com.velocitypowered.api.proxy.player.PlayerSettings; import com.velocitypowered.api.proxy.ConnectionRequestBuilder; +import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.ServerConnection; import com.velocitypowered.api.proxy.messages.ChannelIdentifier; +import com.velocitypowered.api.proxy.player.PlayerSettings; import com.velocitypowered.api.proxy.server.RegisteredServer; +import com.velocitypowered.api.util.GameProfile; import com.velocitypowered.api.util.MessagePosition; -import com.velocitypowered.api.proxy.Player; import com.velocitypowered.proxy.VelocityServer; +import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation; import com.velocitypowered.proxy.connection.VelocityConstants; +import com.velocitypowered.proxy.connection.backend.VelocityServerConnection; import com.velocitypowered.proxy.connection.util.ConnectionMessages; import com.velocitypowered.proxy.connection.util.ConnectionRequestResults; -import com.velocitypowered.api.util.GameProfile; -import com.velocitypowered.proxy.protocol.packet.Chat; -import com.velocitypowered.proxy.connection.MinecraftConnection; -import com.velocitypowered.proxy.connection.backend.VelocityServerConnection; -import com.velocitypowered.proxy.protocol.packet.ClientSettings; -import com.velocitypowered.proxy.protocol.packet.PluginMessage; +import com.velocitypowered.proxy.protocol.packet.*; import com.velocitypowered.proxy.server.VelocityRegisteredServer; import com.velocitypowered.proxy.util.ThrowableUtils; -import com.velocitypowered.api.proxy.server.ServerInfo; -import com.velocitypowered.proxy.protocol.packet.Disconnect; -import com.velocitypowered.proxy.protocol.packet.HeaderAndFooter; - import net.kyori.text.Component; import net.kyori.text.TextComponent; import net.kyori.text.TranslatableComponent; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java index 54899d2a1..6ed3c805c 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java @@ -5,12 +5,12 @@ import com.google.common.collect.ImmutableList; import com.velocitypowered.api.event.connection.ConnectionHandshakeEvent; import com.velocitypowered.api.event.proxy.ProxyPingEvent; import com.velocitypowered.api.proxy.InboundConnection; +import com.velocitypowered.api.proxy.server.ServerPing; import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.config.PlayerInfoForwarding; import com.velocitypowered.proxy.config.VelocityConfiguration; import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; -import com.velocitypowered.api.proxy.server.ServerPing; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.StateRegistry; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialConnectSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialConnectSessionHandler.java index 64273473a..c25298bef 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialConnectSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialConnectSessionHandler.java @@ -1,7 +1,7 @@ package com.velocitypowered.proxy.connection.client; -import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; +import com.velocitypowered.proxy.protocol.MinecraftPacket; public class InitialConnectSessionHandler implements MinecraftSessionHandler { private final ConnectedPlayer player; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java index bf63dc63d..116351ebb 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java @@ -9,17 +9,16 @@ import com.velocitypowered.api.event.permission.PermissionsSetupEvent; import com.velocitypowered.api.event.player.GameProfileRequestEvent; import com.velocitypowered.api.proxy.InboundConnection; import com.velocitypowered.api.proxy.server.RegisteredServer; -import com.velocitypowered.api.proxy.server.ServerInfo; -import com.velocitypowered.proxy.config.PlayerInfoForwarding; -import com.velocitypowered.proxy.connection.VelocityConstants; import com.velocitypowered.api.util.GameProfile; +import com.velocitypowered.proxy.VelocityServer; +import com.velocitypowered.proxy.config.PlayerInfoForwarding; +import com.velocitypowered.proxy.connection.MinecraftConnection; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; +import com.velocitypowered.proxy.connection.VelocityConstants; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.packet.*; -import com.velocitypowered.proxy.connection.MinecraftConnection; -import com.velocitypowered.proxy.connection.MinecraftSessionHandler; -import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.util.EncryptionUtils; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/StatusSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/StatusSessionHandler.java index ccc53a8ac..7c4e84376 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/StatusSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/StatusSessionHandler.java @@ -4,16 +4,16 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.velocitypowered.api.event.proxy.ProxyPingEvent; import com.velocitypowered.api.proxy.InboundConnection; +import com.velocitypowered.api.proxy.server.ServerPing; import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.config.VelocityConfiguration; +import com.velocitypowered.proxy.connection.MinecraftConnection; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.packet.StatusPing; import com.velocitypowered.proxy.protocol.packet.StatusRequest; import com.velocitypowered.proxy.protocol.packet.StatusResponse; -import com.velocitypowered.proxy.connection.MinecraftConnection; -import com.velocitypowered.api.proxy.server.ServerPing; -import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/console/VelocityConsole.java b/proxy/src/main/java/com/velocitypowered/proxy/console/VelocityConsole.java index fcb1d34f9..4e233ddce 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/console/VelocityConsole.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/console/VelocityConsole.java @@ -4,7 +4,9 @@ import com.velocitypowered.proxy.VelocityServer; import net.kyori.text.TextComponent; import net.kyori.text.format.TextColor; import net.minecrell.terminalconsole.SimpleTerminalConsole; -import org.jline.reader.*; +import org.jline.reader.Candidate; +import org.jline.reader.LineReader; +import org.jline.reader.LineReaderBuilder; import java.util.List; import java.util.Optional; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/messages/VelocityChannelRegistrar.java b/proxy/src/main/java/com/velocitypowered/proxy/messages/VelocityChannelRegistrar.java index 1536716cc..c6feff212 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/messages/VelocityChannelRegistrar.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/messages/VelocityChannelRegistrar.java @@ -2,7 +2,10 @@ package com.velocitypowered.proxy.messages; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; -import com.velocitypowered.api.proxy.messages.*; +import com.velocitypowered.api.proxy.messages.ChannelIdentifier; +import com.velocitypowered.api.proxy.messages.ChannelRegistrar; +import com.velocitypowered.api.proxy.messages.LegacyChannelIdentifier; +import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier; import java.util.Collection; import java.util.Map; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java b/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java index 9a115a608..65301cd77 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java @@ -7,21 +7,11 @@ import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.client.HandshakeSessionHandler; import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.StateRegistry; -import com.velocitypowered.proxy.protocol.netty.GS4QueryHandler; -import com.velocitypowered.proxy.protocol.netty.LegacyPingDecoder; -import com.velocitypowered.proxy.protocol.netty.LegacyPingEncoder; -import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder; -import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder; -import com.velocitypowered.proxy.protocol.netty.MinecraftVarintFrameDecoder; -import com.velocitypowered.proxy.protocol.netty.MinecraftVarintLengthEncoder; +import com.velocitypowered.proxy.protocol.netty.*; import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; -import io.netty.channel.epoll.Epoll; -import io.netty.channel.epoll.EpollDatagramChannel; -import io.netty.channel.epoll.EpollEventLoopGroup; -import io.netty.channel.epoll.EpollServerSocketChannel; -import io.netty.channel.epoll.EpollSocketChannel; +import io.netty.channel.epoll.*; import io.netty.channel.kqueue.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.DatagramChannel; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/http/NettyHttpClient.java b/proxy/src/main/java/com/velocitypowered/proxy/network/http/NettyHttpClient.java index 24ab295da..f14f10c40 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/http/NettyHttpClient.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/http/NettyHttpClient.java @@ -2,7 +2,7 @@ package com.velocitypowered.proxy.network.http; import com.velocitypowered.proxy.VelocityServer; import io.netty.bootstrap.Bootstrap; -import io.netty.channel.*; +import io.netty.channel.Channel; import io.netty.channel.pool.*; import io.netty.handler.codec.http.*; import io.netty.handler.ssl.SslContext; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/plugin/VelocityEventManager.java b/proxy/src/main/java/com/velocitypowered/proxy/plugin/VelocityEventManager.java index 3f84e6279..b93afb3fd 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/plugin/VelocityEventManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/plugin/VelocityEventManager.java @@ -13,7 +13,10 @@ import com.velocitypowered.proxy.util.concurrency.RecordingThreadFactory; import net.kyori.event.EventSubscriber; import net.kyori.event.PostResult; import net.kyori.event.SimpleEventBus; -import net.kyori.event.method.*; +import net.kyori.event.method.EventExecutor; +import net.kyori.event.method.MethodScanner; +import net.kyori.event.method.MethodSubscriptionAdapter; +import net.kyori.event.method.SimpleMethodSubscriptionAdapter; import net.kyori.event.method.asm.ASMEventExecutorFactory; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -21,8 +24,13 @@ import org.checkerframework.checker.nullness.qual.NonNull; import java.lang.reflect.Method; import java.net.URL; -import java.util.*; -import java.util.concurrent.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.IdentityHashMap; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; public class VelocityEventManager implements EventManager { private static final Logger logger = LogManager.getLogger(VelocityEventManager.class); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/plugin/VelocityPluginManager.java b/proxy/src/main/java/com/velocitypowered/proxy/plugin/VelocityPluginManager.java index f4625a900..3c1d5b2c5 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/plugin/VelocityPluginManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/plugin/VelocityPluginManager.java @@ -1,7 +1,7 @@ package com.velocitypowered.proxy.plugin; -import com.velocitypowered.api.plugin.PluginDescription; import com.velocitypowered.api.plugin.PluginContainer; +import com.velocitypowered.api.plugin.PluginDescription; import com.velocitypowered.api.plugin.PluginManager; import com.velocitypowered.api.plugin.meta.PluginDependency; import com.velocitypowered.proxy.VelocityServer; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/plugin/loader/JavaPluginLoader.java b/proxy/src/main/java/com/velocitypowered/proxy/plugin/loader/JavaPluginLoader.java index dc26dec3e..09d1df949 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/plugin/loader/JavaPluginLoader.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/plugin/loader/JavaPluginLoader.java @@ -2,7 +2,9 @@ package com.velocitypowered.proxy.plugin.loader; import com.google.inject.Guice; import com.google.inject.Injector; -import com.velocitypowered.api.plugin.*; +import com.velocitypowered.api.plugin.InvalidPluginException; +import com.velocitypowered.api.plugin.PluginContainer; +import com.velocitypowered.api.plugin.PluginDescription; import com.velocitypowered.api.plugin.meta.PluginDependency; import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.proxy.VelocityServer; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/plugin/loader/java/VelocityPluginModule.java b/proxy/src/main/java/com/velocitypowered/proxy/plugin/loader/java/VelocityPluginModule.java index cc3ddadc2..66e116eeb 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/plugin/loader/java/VelocityPluginModule.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/plugin/loader/java/VelocityPluginModule.java @@ -8,7 +8,6 @@ import com.velocitypowered.api.plugin.PluginDescription; import com.velocitypowered.api.plugin.PluginManager; import com.velocitypowered.api.plugin.annotation.DataDirectory; import com.velocitypowered.api.proxy.ProxyServer; -import com.velocitypowered.proxy.VelocityServer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java index f343adae4..8056c3823 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -8,7 +8,7 @@ import io.netty.util.collection.IntObjectMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import java.util.*; +import java.util.Objects; import java.util.function.Supplier; import static com.velocitypowered.proxy.protocol.ProtocolConstants.*; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java index 61893ff44..95b218056 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java @@ -1,8 +1,8 @@ package com.velocitypowered.proxy.protocol.netty; import com.google.common.base.Preconditions; -import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.natives.compression.VelocityCompressor; +import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageDecoder; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressEncoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressEncoder.java index 802f45121..48ded65a5 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressEncoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressEncoder.java @@ -1,7 +1,7 @@ package com.velocitypowered.proxy.protocol.netty; -import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.natives.compression.VelocityCompressor; +import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java index 07ddb287f..4b7e00232 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java @@ -1,7 +1,10 @@ package com.velocitypowered.proxy.protocol.netty; import com.google.common.base.Preconditions; -import com.velocitypowered.proxy.protocol.*; +import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolConstants; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import com.velocitypowered.proxy.protocol.StateRegistry; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.CorruptedFrameException; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintLengthEncoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintLengthEncoder.java index 7a0d61c92..3116c6a69 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintLengthEncoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintLengthEncoder.java @@ -4,7 +4,6 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.MessageToByteEncoder; import io.netty.handler.codec.MessageToMessageEncoder; import java.util.List; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/Chat.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/Chat.java index c3de9c6b9..f289b7c54 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/Chat.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/Chat.java @@ -1,8 +1,8 @@ package com.velocitypowered.proxy.protocol.packet; import com.google.common.base.Preconditions; -import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; import net.kyori.text.Component; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/Disconnect.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/Disconnect.java index 1420b7981..f6dfd877a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/Disconnect.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/Disconnect.java @@ -1,8 +1,8 @@ package com.velocitypowered.proxy.protocol.packet; import com.google.common.base.Preconditions; -import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; import net.kyori.text.Component; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/Handshake.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/Handshake.java index dec9ecb4a..aef59ec2b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/Handshake.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/Handshake.java @@ -1,7 +1,7 @@ package com.velocitypowered.proxy.protocol.packet; -import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HeaderAndFooter.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HeaderAndFooter.java index 35c75af30..6ee851d65 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HeaderAndFooter.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HeaderAndFooter.java @@ -2,13 +2,13 @@ package com.velocitypowered.proxy.protocol.packet; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolConstants.Direction; -import static com.velocitypowered.proxy.protocol.ProtocolUtils.writeString; - import io.netty.buffer.ByteBuf; import net.kyori.text.Component; import net.kyori.text.serializer.ComponentSerializer; import net.kyori.text.serializer.ComponentSerializers; +import static com.velocitypowered.proxy.protocol.ProtocolUtils.writeString; + public class HeaderAndFooter implements MinecraftPacket { private static final HeaderAndFooter RESET = new HeaderAndFooter("{\"translate\":\"\"}", "{\"translate\":\"\"}"); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/KeepAlive.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/KeepAlive.java index 638b15d52..1e491b61b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/KeepAlive.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/KeepAlive.java @@ -1,7 +1,7 @@ package com.velocitypowered.proxy.protocol.packet; -import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLogin.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLogin.java index 459afe338..a9cb0ac68 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLogin.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLogin.java @@ -1,7 +1,7 @@ package com.velocitypowered.proxy.protocol.packet; -import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusRequest.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusRequest.java index ff9897c69..33e1e1411 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusRequest.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusRequest.java @@ -1,7 +1,7 @@ package com.velocitypowered.proxy.protocol.packet; -import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolConstants; import io.netty.buffer.ByteBuf; public class StatusRequest implements MinecraftPacket { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusResponse.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusResponse.java index 75a052258..7c397fa83 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusResponse.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusResponse.java @@ -1,7 +1,7 @@ package com.velocitypowered.proxy.protocol.packet; -import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/util/PluginMessageUtil.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/util/PluginMessageUtil.java index e3fdeab31..1ffb37dc9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/util/PluginMessageUtil.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/util/PluginMessageUtil.java @@ -5,7 +5,6 @@ import com.google.common.collect.ImmutableList; import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.packet.PluginMessage; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import java.nio.charset.StandardCharsets; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java b/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java index 6f61cea06..0b0d110d9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java @@ -16,7 +16,6 @@ import java.util.Collection; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicReference; public class VelocityScheduler implements Scheduler { private final PluginManager pluginManager; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/ServerMap.java b/proxy/src/main/java/com/velocitypowered/proxy/server/ServerMap.java index 247b5ebfe..2216387e7 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/ServerMap.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/ServerMap.java @@ -6,7 +6,10 @@ import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.proxy.VelocityServer; -import java.util.*; +import java.util.Collection; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; public class ServerMap { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java b/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java index b937fc926..7abd379f0 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java @@ -23,16 +23,13 @@ import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelInitializer; import io.netty.handler.timeout.ReadTimeoutHandler; -import java.util.*; +import java.util.Collection; +import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; import static com.velocitypowered.proxy.network.Connections.*; -import static com.velocitypowered.proxy.network.Connections.HANDLER; -import static com.velocitypowered.proxy.network.Connections.MINECRAFT_ENCODER; public class VelocityRegisteredServer implements RegisteredServer { private final VelocityServer server; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/util/concurrency/RecordingThreadFactory.java b/proxy/src/main/java/com/velocitypowered/proxy/util/concurrency/RecordingThreadFactory.java index ae289bb1c..1de4b165d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/util/concurrency/RecordingThreadFactory.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/util/concurrency/RecordingThreadFactory.java @@ -6,7 +6,6 @@ import com.google.common.collect.MapMaker; import java.util.Collections; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadFactory; /** diff --git a/proxy/src/test/java/com/velocitypowered/proxy/protocol/PacketRegistryTest.java b/proxy/src/test/java/com/velocitypowered/proxy/protocol/PacketRegistryTest.java index dac88e563..cc227f471 100644 --- a/proxy/src/test/java/com/velocitypowered/proxy/protocol/PacketRegistryTest.java +++ b/proxy/src/test/java/com/velocitypowered/proxy/protocol/PacketRegistryTest.java @@ -3,9 +3,7 @@ package com.velocitypowered.proxy.protocol; import com.velocitypowered.proxy.protocol.packet.Handshake; import org.junit.jupiter.api.Test; -import static com.velocitypowered.proxy.protocol.ProtocolConstants.MINECRAFT_1_12; -import static com.velocitypowered.proxy.protocol.ProtocolConstants.MINECRAFT_1_12_1; -import static com.velocitypowered.proxy.protocol.ProtocolConstants.MINECRAFT_1_12_2; +import static com.velocitypowered.proxy.protocol.ProtocolConstants.*; import static org.junit.jupiter.api.Assertions.*; class PacketRegistryTest { diff --git a/proxy/src/test/java/com/velocitypowered/proxy/scheduler/VelocitySchedulerTest.java b/proxy/src/test/java/com/velocitypowered/proxy/scheduler/VelocitySchedulerTest.java index d6d6896ee..7be0008c8 100644 --- a/proxy/src/test/java/com/velocitypowered/proxy/scheduler/VelocitySchedulerTest.java +++ b/proxy/src/test/java/com/velocitypowered/proxy/scheduler/VelocitySchedulerTest.java @@ -9,7 +9,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; class VelocitySchedulerTest { // TODO: The timings here will be inaccurate on slow systems. Need to find a testing-friendly replacement for Thread.sleep() diff --git a/proxy/src/test/java/com/velocitypowered/proxy/util/RatelimiterTest.java b/proxy/src/test/java/com/velocitypowered/proxy/util/RatelimiterTest.java index b9f9ff204..ba97fc493 100644 --- a/proxy/src/test/java/com/velocitypowered/proxy/util/RatelimiterTest.java +++ b/proxy/src/test/java/com/velocitypowered/proxy/util/RatelimiterTest.java @@ -7,7 +7,8 @@ import java.net.InetAddress; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; class RatelimiterTest { diff --git a/proxy/src/test/java/com/velocitypowered/proxy/util/ServerMapTest.java b/proxy/src/test/java/com/velocitypowered/proxy/util/ServerMapTest.java index ad8d3d52b..4105fdac7 100644 --- a/proxy/src/test/java/com/velocitypowered/proxy/util/ServerMapTest.java +++ b/proxy/src/test/java/com/velocitypowered/proxy/util/ServerMapTest.java @@ -9,7 +9,8 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.Optional; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; class ServerMapTest { private static final InetSocketAddress TEST_ADDRESS = new InetSocketAddress(InetAddress.getLoopbackAddress(), 25565); From 5c3e1adee2deb717b67706589ba401cba84b3cb4 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Wed, 19 Sep 2018 14:57:53 -0400 Subject: [PATCH 41/45] Fix this annoying wart --- .../java/com/velocitypowered/api/scheduler/Scheduler.java | 4 ++-- .../velocitypowered/proxy/scheduler/VelocityScheduler.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/scheduler/Scheduler.java b/api/src/main/java/com/velocitypowered/api/scheduler/Scheduler.java index fd652d1c6..2854a664c 100644 --- a/api/src/main/java/com/velocitypowered/api/scheduler/Scheduler.java +++ b/api/src/main/java/com/velocitypowered/api/scheduler/Scheduler.java @@ -24,7 +24,7 @@ public interface Scheduler { * @param unit the unit of time for {@code time} * @return this builder, for chaining */ - TaskBuilder delay(int time, TimeUnit unit); + TaskBuilder delay(long time, TimeUnit unit); /** * Specifies that the task should continue running after waiting for the specified amount, until it is cancelled. @@ -32,7 +32,7 @@ public interface Scheduler { * @param unit the unit of time for {@code time} * @return this builder, for chaining */ - TaskBuilder repeat(int time, TimeUnit unit); + TaskBuilder repeat(long time, TimeUnit unit); /** * Clears the delay on this task. diff --git a/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java b/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java index 0b0d110d9..d37abc0e3 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java @@ -65,13 +65,13 @@ public class VelocityScheduler implements Scheduler { } @Override - public TaskBuilder delay(int time, TimeUnit unit) { + public TaskBuilder delay(long time, TimeUnit unit) { this.delay = unit.toMillis(time); return this; } @Override - public TaskBuilder repeat(int time, TimeUnit unit) { + public TaskBuilder repeat(long time, TimeUnit unit) { this.repeat = unit.toMillis(time); return this; } From b7e6334324112418888b827f4a9c68f895abdc5b Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Wed, 19 Sep 2018 15:20:18 -0400 Subject: [PATCH 42/45] Add toString() to PluginMessageEvent --- .../api/event/connection/PluginMessageEvent.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/api/src/main/java/com/velocitypowered/api/event/connection/PluginMessageEvent.java b/api/src/main/java/com/velocitypowered/api/event/connection/PluginMessageEvent.java index 4caf3280c..b16f933e4 100644 --- a/api/src/main/java/com/velocitypowered/api/event/connection/PluginMessageEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/connection/PluginMessageEvent.java @@ -60,6 +60,17 @@ public class PluginMessageEvent implements ResultedEvent getModList() { + return modList; + } } public static class Mod { From 1bdba0075f8753ed5b41401eac56c8b6e170be0c Mon Sep 17 00:00:00 2001 From: PurpleIsEverything Date: Wed, 19 Sep 2018 17:13:29 -0600 Subject: [PATCH 44/45] Rename getModList to getMods --- .../java/com/velocitypowered/api/proxy/server/ServerPing.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java b/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java index 0c9feffb3..bf9a3f2ee 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java @@ -317,7 +317,7 @@ public class ServerPing { return type; } - public List getModList() { + public List getMods() { return modList; } } From 95c761479f870dae3bb0a1dfafca33126faa4ed0 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Wed, 19 Sep 2018 21:29:07 -0400 Subject: [PATCH 45/45] Make connections more robust --- .../connection/client/ConnectedPlayer.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java index 032f7c8fa..8917fec7e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java @@ -262,17 +262,21 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { return server.getServers().getServer(toTryName); } - private CompletableFuture connect(ConnectionRequestBuilderImpl request) { + private Optional checkServer(RegisteredServer server) { + Preconditions.checkState(server instanceof VelocityRegisteredServer, "Not a valid Velocity server."); if (connectionInFlight != null) { - return CompletableFuture.completedFuture( - ConnectionRequestResults.plainResult(ConnectionRequestBuilder.Status.CONNECTION_IN_PROGRESS) - ); + return Optional.of(ConnectionRequestBuilder.Status.CONNECTION_IN_PROGRESS); } + if (connectedServer != null && connectedServer.getServer().equals(server)) { + return Optional.of(ConnectionRequestBuilder.Status.ALREADY_CONNECTED); + } + return Optional.empty(); + } - if (connectedServer != null && connectedServer.getServerInfo().equals(request.getServer())) { - return CompletableFuture.completedFuture( - ConnectionRequestResults.plainResult(ConnectionRequestBuilder.Status.ALREADY_CONNECTED) - ); + private CompletableFuture connect(ConnectionRequestBuilderImpl request) { + Optional initialCheck = checkServer(request.getServer()); + if (initialCheck.isPresent()) { + return CompletableFuture.completedFuture(ConnectionRequestResults.plainResult(initialCheck.get())); } // Otherwise, initiate the connection. @@ -286,7 +290,10 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { } RegisteredServer rs = newEvent.getResult().getServer().get(); - Preconditions.checkState(rs instanceof VelocityRegisteredServer, "Not a valid Velocity server."); + Optional lastCheck = checkServer(rs); + if (lastCheck.isPresent()) { + return CompletableFuture.completedFuture(ConnectionRequestResults.plainResult(lastCheck.get())); + } return new VelocityServerConnection((VelocityRegisteredServer) rs, this, server).connect(); }); }