From d0cbcf65e92ef2f0cf150887d4ca8f14f7bbabbe Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sun, 19 Apr 2020 09:07:17 -0400 Subject: [PATCH 01/36] Fix some tab-complete regressions --- .../proxy/command/VelocityCommandManager.java | 9 ++++++++- .../connection/client/ClientPlaySessionHandler.java | 8 ++++---- 2 files changed, 12 insertions(+), 5 deletions(-) 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 4b85bdef6..a7742980c 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java @@ -167,7 +167,14 @@ public class VelocityCommandManager implements CommandManager { if (line.isEmpty()) { return new String[0]; } - return line.trim().split(" ", -1); + + String[] trimmed = line.trim().split(" ", -1); + if (line.endsWith(" ") && !line.trim().isEmpty()) { + // To work around a 1.13+ specific bug we have to inject a space at the end of the arguments + trimmed = Arrays.copyOf(trimmed, trimmed.length + 1); + trimmed[trimmed.length - 1] = ""; + } + return trimmed; } @Override 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 f68448d8c..35d149c24 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 @@ -365,12 +365,12 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { private boolean handleCommandTabComplete(TabCompleteRequest packet) { // In 1.13+, we need to do additional work for the richer suggestions available. String command = packet.getCommand().substring(1); - int spacePos = command.indexOf(' '); - if (spacePos == -1) { - spacePos = command.length(); + int commandEndPosition = command.indexOf(' '); + if (commandEndPosition == -1) { + commandEndPosition = command.length(); } - String commandLabel = command.substring(0, spacePos); + String commandLabel = command.substring(0, commandEndPosition); if (!server.getCommandManager().hasCommand(commandLabel)) { if (player.getProtocolVersion().compareTo(MINECRAFT_1_13) < 0) { // Outstanding tab completes are recorded for use with 1.12 clients and below to provide From 24c9fc0ef1f110ca8d44d5e7ce24279ae7d8563a Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sun, 19 Apr 2020 09:20:03 -0400 Subject: [PATCH 02/36] Relax GameProfileRequestEvent#setGameProfile to allow faking even in online-mode --- .../api/event/player/GameProfileRequestEvent.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 6574f9d7b..4c209056a 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 @@ -60,13 +60,11 @@ public final class GameProfileRequestEvent { } /** - * Sets the game profile to use for this connection. It is invalid to use this method on an - * online-mode connection. + * Sets the game profile to use for this connection. * * @param gameProfile the profile for this connection, {@code null} uses the original profile */ public void setGameProfile(@Nullable GameProfile gameProfile) { - Preconditions.checkState(!onlineMode, "Profiles can not be faked in online mode!"); this.gameProfile = gameProfile; } From 2b84d35798a72f96427edf4cdf1c81bd17fa66e0 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Tue, 21 Apr 2020 06:23:04 -0400 Subject: [PATCH 03/36] Fix bug in ConnectOther message Credits to @Jay113355 for spotting this --- .../connection/backend/BungeeCordMessageResponder.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BungeeCordMessageResponder.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BungeeCordMessageResponder.java index 678c77e8f..911e803cd 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BungeeCordMessageResponder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BungeeCordMessageResponder.java @@ -15,6 +15,7 @@ import com.velocitypowered.proxy.protocol.util.ByteBufDataOutput; import com.velocitypowered.proxy.server.VelocityRegisteredServer; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import java.util.Optional; import java.util.StringJoiner; import net.kyori.text.serializer.legacy.LegacyComponentSerializer; @@ -43,8 +44,11 @@ class BungeeCordMessageResponder { String playerName = in.readUTF(); String serverName = in.readUTF(); - proxy.getPlayer(playerName).flatMap(player -> proxy.getServer(serverName)) - .ifPresent(server -> player.createConnectionRequest(server).fireAndForget()); + Optional referencedPlayer = proxy.getPlayer(playerName); + Optional referencedServer = proxy.getServer(serverName); + if (referencedPlayer.isPresent() && referencedServer.isPresent()) { + referencedPlayer.get().createConnectionRequest(referencedServer.get()).fireAndForget(); + } } private void processIp(ByteBufDataInput in) { From e6ea191c92dbc745f4884701b449830bd8d61042 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Wed, 22 Apr 2020 10:27:08 -0400 Subject: [PATCH 04/36] Bump Netty to 4.1.49.Final This is intended to fix netty/netty#10165 directly, and supersede our current workaround. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2e57eb060..d3d19cdc9 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ allprojects { junitVersion = '5.3.0-M1' slf4jVersion = '1.7.25' log4jVersion = '2.11.2' - nettyVersion = '4.1.43.Final' + nettyVersion = '4.1.49.Final' guavaVersion = '25.1-jre' checkerFrameworkVersion = '2.7.0' configurateVersion = '3.6' From 81a0cbe3b9ff0373e598019f975b255bac50e636 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sun, 19 Apr 2020 03:39:15 -0400 Subject: [PATCH 05/36] Fix rare race condition with transitioning If the player unexpectedly disconnects after ServerConnectEvent is fired, but before the connection transitions to the new player, Velocity would throw an exception thinking the connection was not present. This is the correct behavior, but the behavior is very surprising. Instead we will double-check to ensure the connection has not been lost before we continue with transitioning to the new server. --- .../proxy/connection/backend/TransitionSessionHandler.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java index c5eb9d8d6..119e03785 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java @@ -83,6 +83,13 @@ public class TransitionSessionHandler implements MinecraftSessionHandler { .fire(new ServerConnectedEvent(serverConn.getPlayer(), serverConn.getServer(), existingConnection != null ? existingConnection.getServer() : null)) .whenCompleteAsync((x, error) -> { + // Make sure we can still transition (player might have disconnected here). + if (!serverConn.isActive()) { + // Connection is obsolete. + serverConn.disconnect(); + return; + } + // Strap on the ClientPlaySessionHandler if required. ClientPlaySessionHandler playHandler; if (serverConn.getPlayer().getConnection().getSessionHandler() From 957c0dd307b4a4f624ba24e95092c49813a35493 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Thu, 23 Apr 2020 16:19:49 -0400 Subject: [PATCH 06/36] Implement brigadier:long argument type, fixes #295 --- api/build.gradle | 1 + proxy/build.gradle | 2 +- .../brigadier/ArgumentPropertyRegistry.java | 3 ++ .../packet/brigadier/DummyProperty.java | 10 ++--- .../LongArgumentPropertySerializer.java | 40 +++++++++++++++++++ 5 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/LongArgumentPropertySerializer.java diff --git a/api/build.gradle b/api/build.gradle index edf3dc198..b156d61fc 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -63,6 +63,7 @@ artifacts { javadoc { options.encoding = 'UTF-8' options.charSet = 'UTF-8' + options.source = '8' options.links( 'http://www.slf4j.org/apidocs/', 'https://google.github.io/guava/releases/25.1-jre/api/docs/', diff --git a/proxy/build.gradle b/proxy/build.gradle index 216e58cc8..5498db10b 100644 --- a/proxy/build.gradle +++ b/proxy/build.gradle @@ -65,7 +65,7 @@ dependencies { compile 'it.unimi.dsi:fastutil:8.2.3' compile 'net.kyori:event-method-asm:3.0.0' - compile 'com.mojang:brigadier:1.0.15' + compile 'com.mojang:brigadier:1.0.17' compile 'org.asynchttpclient:async-http-client:2.10.4' diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentPropertyRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentPropertyRegistry.java index 9560a8b29..e7847ec8e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentPropertyRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentPropertyRegistry.java @@ -4,6 +4,7 @@ import static com.velocitypowered.proxy.protocol.packet.brigadier.DoubleArgument import static com.velocitypowered.proxy.protocol.packet.brigadier.DummyVoidArgumentPropertySerializer.DUMMY; import static com.velocitypowered.proxy.protocol.packet.brigadier.FloatArgumentPropertySerializer.FLOAT; import static com.velocitypowered.proxy.protocol.packet.brigadier.IntegerArgumentPropertySerializer.INTEGER; +import static com.velocitypowered.proxy.protocol.packet.brigadier.LongArgumentPropertySerializer.LONG; import static com.velocitypowered.proxy.protocol.packet.brigadier.StringArgumentPropertySerializer.STRING; import com.mojang.brigadier.arguments.ArgumentType; @@ -11,6 +12,7 @@ import com.mojang.brigadier.arguments.BoolArgumentType; import com.mojang.brigadier.arguments.DoubleArgumentType; import com.mojang.brigadier.arguments.FloatArgumentType; import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.arguments.LongArgumentType; import com.mojang.brigadier.arguments.StringArgumentType; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; @@ -90,6 +92,7 @@ public class ArgumentPropertyRegistry { register("brigadier:double", DoubleArgumentType.class, DOUBLE); register("brigadier:bool", BoolArgumentType.class, VoidArgumentPropertySerializer.create(BoolArgumentType::bool)); + register("brigadier:long", LongArgumentType.class, LONG); // Minecraft argument types with extra properties dummy("minecraft:entity", ByteArgumentPropertySerializer.BYTE); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/DummyProperty.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/DummyProperty.java index 762b52686..9b514f903 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/DummyProperty.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/DummyProperty.java @@ -17,11 +17,6 @@ class DummyProperty implements ArgumentType { this.result = result; } - @Override - public T parse(StringReader reader) throws CommandSyntaxException { - throw new UnsupportedOperationException(); - } - public String getIdentifier() { return identifier; } @@ -33,4 +28,9 @@ class DummyProperty implements ArgumentType { public @Nullable T getResult() { return result; } + + @Override + public T parse(StringReader reader) { + throw new UnsupportedOperationException(); + } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/LongArgumentPropertySerializer.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/LongArgumentPropertySerializer.java new file mode 100644 index 000000000..9d3b40b6d --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/LongArgumentPropertySerializer.java @@ -0,0 +1,40 @@ +package com.velocitypowered.proxy.protocol.packet.brigadier; + +import static com.velocitypowered.proxy.protocol.packet.brigadier.IntegerArgumentPropertySerializer.HAS_MAXIMUM; +import static com.velocitypowered.proxy.protocol.packet.brigadier.IntegerArgumentPropertySerializer.HAS_MINIMUM; +import static com.velocitypowered.proxy.protocol.packet.brigadier.IntegerArgumentPropertySerializer.getFlags; + +import com.mojang.brigadier.arguments.LongArgumentType; +import io.netty.buffer.ByteBuf; + +class LongArgumentPropertySerializer implements ArgumentPropertySerializer { + + static final LongArgumentPropertySerializer LONG = new LongArgumentPropertySerializer(); + + private LongArgumentPropertySerializer() { + + } + + @Override + public LongArgumentType deserialize(ByteBuf buf) { + byte flags = buf.readByte(); + long minimum = (flags & HAS_MINIMUM) != 0 ? buf.readLong() : Long.MIN_VALUE; + long maximum = (flags & HAS_MAXIMUM) != 0 ? buf.readLong() : Long.MAX_VALUE; + return LongArgumentType.longArg(minimum, maximum); + } + + @Override + public void serialize(LongArgumentType object, ByteBuf buf) { + boolean hasMinimum = object.getMinimum() != Long.MIN_VALUE; + boolean hasMaximum = object.getMaximum() != Long.MAX_VALUE; + byte flag = getFlags(hasMinimum, hasMaximum); + + buf.writeByte(flag); + if (hasMinimum) { + buf.writeLong(object.getMinimum()); + } + if (hasMaximum) { + buf.writeLong(object.getMaximum()); + } + } +} From 6555e0e337add5c2fc66ad8367a95a1c0c48ecfc Mon Sep 17 00:00:00 2001 From: Leymooo Date: Mon, 27 Apr 2020 00:04:12 +0300 Subject: [PATCH 07/36] Add CommandExecuteEvent --- .../api/command/CommandManager.java | 11 ++ .../event/command/CommandExecuteEvent.java | 143 ++++++++++++++++++ .../api/event/player/PlayerChatEvent.java | 10 +- .../velocitypowered/proxy/VelocityServer.java | 3 +- .../proxy/command/VelocityCommandManager.java | 38 +++++ .../client/ClientPlaySessionHandler.java | 38 +++-- .../proxy/console/VelocityConsole.java | 2 +- 7 files changed, 226 insertions(+), 19 deletions(-) create mode 100644 api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java diff --git a/api/src/main/java/com/velocitypowered/api/command/CommandManager.java b/api/src/main/java/com/velocitypowered/api/command/CommandManager.java index 81a7b8297..ce3452e40 100644 --- a/api/src/main/java/com/velocitypowered/api/command/CommandManager.java +++ b/api/src/main/java/com/velocitypowered/api/command/CommandManager.java @@ -35,10 +35,21 @@ public interface CommandManager { /** * Attempts to execute a command from the specified {@code cmdLine}. + * CommandExecuteEvent will not called * * @param source the command's source * @param cmdLine the command to run * @return true if the command was found and executed, false if it was not */ boolean execute(CommandSource source, String cmdLine); + + /** + * Attempts to execute a command from the specified {@code cmdLine}. + * + * @param source the command's source + * @param cmdLine the command to run + * @param callEvent will CommandExecuteEvent called or not + * @return true if the command was found and executed, false if it was not + */ + boolean execute(CommandSource source, String cmdLine, boolean callEvent); } diff --git a/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java b/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java new file mode 100644 index 000000000..f92ed6892 --- /dev/null +++ b/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java @@ -0,0 +1,143 @@ +package com.velocitypowered.api.event.command; + +import com.google.common.base.Preconditions; +import com.velocitypowered.api.command.CommandSource; +import com.velocitypowered.api.event.ResultedEvent; +import com.velocitypowered.api.event.command.CommandExecuteEvent.CommandResult; +import java.util.Optional; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * This event is fired when a player types in a chat message. + */ +public final class CommandExecuteEvent implements ResultedEvent { + + private final CommandSource commandSource; + private final String command; + private CommandResult result; + + /** + * Constructs a PlayerChatEvent. + * @param commandSource the source executing the command + * @param command the command being executed without first slash + */ + public CommandExecuteEvent(CommandSource commandSource, String command) { + this.commandSource = Preconditions.checkNotNull(commandSource, "commandSource"); + this.command = Preconditions.checkNotNull(command, "command"); + this.result = CommandResult.allowed(); + } + + public CommandSource getCommandSource() { + return commandSource; + } + + /** + * Gets the original command being executed without first slash. + * @return the original command being executed + */ + public String getCommand() { + return command; + } + + @Override + public CommandResult getResult() { + return result; + } + + @Override + public void setResult(CommandResult result) { + this.result = Preconditions.checkNotNull(result, "result"); + } + + @Override + public String toString() { + return "PlayerCommmandEvent{" + + "commandSource=" + commandSource + + ", command=" + command + + ", result=" + result + + '}'; + } + + /** + * Represents the result of the {@link CommandExecuteEvent}. + */ + public static final class CommandResult implements Result { + + private static final CommandResult ALLOWED = new CommandResult(true, false,null); + private static final CommandResult DENIED = new CommandResult(false, false,null); + private static final CommandResult FORWARD_TO_SERVER = new CommandResult(false, true, null); + + private @Nullable String command; + private final boolean status; + private final boolean forward; + + private CommandResult(boolean status, boolean forward, @Nullable String command) { + this.status = status; + this.forward = forward; + this.command = command; + } + + public Optional getCommand() { + return Optional.ofNullable(command); + } + + public boolean isForwardToServer() { + return forward; + } + + @Override + public boolean isAllowed() { + return status; + } + + @Override + public String toString() { + return status ? "allowed" : "denied"; + } + + /** + * Allows the command to be sent, without modification. + * @return the allowed result + */ + public static CommandResult allowed() { + return ALLOWED; + } + + /** + * Prevents the command from being executed. + * @return the denied result + */ + public static CommandResult denied() { + return DENIED; + } + + /** + * Prevents the command from being executed, but forward command to server. + * @return the forward result + */ + public static CommandResult forwardToServer() { + return FORWARD_TO_SERVER; + } + + /** + * Prevents the command from being executed on proxy, but forward command to server. + * @param newCommand the command without first slash to use instead + * @return a result with a new command being forwarded to server + */ + public static CommandResult forwardToServer(@NonNull String newCommand) { + Preconditions.checkNotNull(newCommand, "newCommand"); + return new CommandResult(false, true, newCommand); + } + + /** + * Allows the command to be executed, but silently replaced old command with another. + * @param newCommand the command to use instead without first slash + * @return a result with a new command + */ + public static CommandResult command(@NonNull String newCommand) { + Preconditions.checkNotNull(newCommand, "newCommand"); + return new CommandResult(true, false, newCommand); + } + } +} diff --git a/api/src/main/java/com/velocitypowered/api/event/player/PlayerChatEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/PlayerChatEvent.java index 6b8b7bba1..ef77c96a4 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/PlayerChatEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/PlayerChatEvent.java @@ -70,6 +70,10 @@ public final class PlayerChatEvent implements ResultedEvent getMessage() { + return Optional.ofNullable(message); + } + @Override public boolean isAllowed() { return status; @@ -96,10 +100,6 @@ public final class PlayerChatEvent implements ResultedEvent getMessage() { - return Optional.ofNullable(message); - } - /** * Allows the message to be sent, but silently replaced with another. * @param message the message to use instead @@ -110,6 +110,4 @@ public final class PlayerChatEvent implements ResultedEvent commands = new HashMap<>(); + private final EventManager eventManager; + + public VelocityCommandManager(EventManager eventManager) { + this.eventManager = eventManager; + } @Override @Deprecated @@ -47,11 +57,39 @@ public class VelocityCommandManager implements CommandManager { this.commands.remove(alias.toLowerCase(Locale.ENGLISH)); } + /** + * Calls CommandExecuteEvent. + * @param source the command's source + * @param cmd the command + * @return CompletableFuture of event + */ + public CompletableFuture callCommandEvent(CommandSource source, String cmd) { + Preconditions.checkNotNull(source, "invoker"); + Preconditions.checkNotNull(cmd, "cmd"); + return eventManager.fire(new CommandExecuteEvent(source, cmd)); + } + @Override public boolean execute(CommandSource source, String cmdLine) { Preconditions.checkNotNull(source, "invoker"); Preconditions.checkNotNull(cmdLine, "cmdLine"); + return execute(source, cmdLine, false); + } + + @Override + public boolean execute(CommandSource source, String cmdLine, boolean callEvent) { + Preconditions.checkNotNull(source, "invoker"); + Preconditions.checkNotNull(cmdLine, "cmdLine"); + + if (callEvent) { + CommandExecuteEvent event = callCommandEvent(source, cmdLine).join(); + CommandResult commandResult = event.getResult(); + if (commandResult.isForwardToServer() || !commandResult.isAllowed()) { + return false; + } + cmdLine = commandResult.getCommand().orElse(event.getCommand()); + } String alias = cmdLine; String args = ""; int firstSpace = cmdLine.indexOf(' '); 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 35d149c24..f1bbaf1c8 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 static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_13; import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_8; import static com.velocitypowered.proxy.protocol.util.PluginMessageUtil.constructChannelsPacket; +import com.velocitypowered.api.event.command.CommandExecuteEvent; import com.velocitypowered.api.event.connection.PluginMessageEvent; import com.velocitypowered.api.event.player.PlayerChatEvent; import com.velocitypowered.api.event.player.PlayerResourcePackStatusEvent; @@ -123,17 +124,32 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { String msg = packet.getMessage(); if (msg.startsWith("/")) { - try { - if (!server.getCommandManager().execute(player, msg.substring(1))) { - return false; - } - } catch (Exception e) { - logger.info("Exception occurred while running command for {}", player.getUsername(), - e); - player.sendMessage( - TextComponent.of("An error occurred while running this command.", TextColor.RED)); - return true; - } + + server.getCommandManager().callCommandEvent(player, msg.substring(1)) + .thenAcceptAsync(event -> { + CommandExecuteEvent.CommandResult commandResult = event.getResult(); + if (commandResult.isAllowed()) { + Optional eventCommand = event.getResult().getCommand(); + String command = eventCommand.orElse(event.getCommand()); + + if (commandResult.isForwardToServer()) { + smc.write(Chat.createServerbound(command)); + return; + } + + try { + if (!server.getCommandManager().execute(player, command)) { + smc.write(Chat.createServerbound(command)); + } + } catch (Exception e) { + logger.info("Exception occurred while running command for {}", player.getUsername(), + e); + player.sendMessage( + TextComponent.of("An error occurred while running this command.", + TextColor.RED)); + } + } + }); } else { PlayerChatEvent event = new PlayerChatEvent(player, msg); server.getEventManager().fire(event) 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 4b9d38aee..0123db3e1 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/console/VelocityConsole.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/console/VelocityConsole.java @@ -91,7 +91,7 @@ public final class VelocityConsole extends SimpleTerminalConsole implements Cons @Override protected void runCommand(String command) { try { - if (!this.server.getCommandManager().execute(this, command)) { + if (!this.server.getCommandManager().execute(this, command, true)) { sendMessage(TextComponent.of("Command not found.", TextColor.RED)); } } catch (Exception e) { From 1fb382e0f6b4fcb7c2100cabe0a284ce01862e89 Mon Sep 17 00:00:00 2001 From: Leymooo Date: Mon, 27 Apr 2020 00:09:25 +0300 Subject: [PATCH 08/36] fix logic --- .../client/ClientPlaySessionHandler.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 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 f1bbaf1c8..9c22e9c2c 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 @@ -128,15 +128,13 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { server.getCommandManager().callCommandEvent(player, msg.substring(1)) .thenAcceptAsync(event -> { CommandExecuteEvent.CommandResult commandResult = event.getResult(); + Optional eventCommand = event.getResult().getCommand(); + String command = eventCommand.orElse(event.getCommand()); + if (commandResult.isForwardToServer()) { + smc.write(Chat.createServerbound(command)); + return; + } if (commandResult.isAllowed()) { - Optional eventCommand = event.getResult().getCommand(); - String command = eventCommand.orElse(event.getCommand()); - - if (commandResult.isForwardToServer()) { - smc.write(Chat.createServerbound(command)); - return; - } - try { if (!server.getCommandManager().execute(player, command)) { smc.write(Chat.createServerbound(command)); From fb64333813699b4f1ade5c9a0646f8d4f7460713 Mon Sep 17 00:00:00 2001 From: Leymooo Date: Mon, 27 Apr 2020 00:11:49 +0300 Subject: [PATCH 09/36] pass eventLoop to thenApplyAsync --- .../proxy/connection/client/ClientPlaySessionHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 9c22e9c2c..4864bcf22 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 @@ -147,7 +147,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { TextColor.RED)); } } - }); + }, smc.eventLoop()); } else { PlayerChatEvent event = new PlayerChatEvent(player, msg); server.getEventManager().fire(event) From c0b8e9d646cf94877c89f0b6d631ebb484f58ca2 Mon Sep 17 00:00:00 2001 From: Leymooo Date: Mon, 27 Apr 2020 01:05:57 +0300 Subject: [PATCH 10/36] add async methods, also add separate methods which will call event and which will not call event --- .../api/command/CommandManager.java | 32 +++++++++-- .../proxy/command/VelocityCommandManager.java | 57 ++++++++++++++----- .../client/ClientPlaySessionHandler.java | 2 +- .../proxy/console/VelocityConsole.java | 4 +- .../proxy/plugin/VelocityEventManager.java | 4 ++ 5 files changed, 79 insertions(+), 20 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/command/CommandManager.java b/api/src/main/java/com/velocitypowered/api/command/CommandManager.java index ce3452e40..af200cb74 100644 --- a/api/src/main/java/com/velocitypowered/api/command/CommandManager.java +++ b/api/src/main/java/com/velocitypowered/api/command/CommandManager.java @@ -1,5 +1,7 @@ package com.velocitypowered.api.command; +import java.util.concurrent.CompletableFuture; + /** * Represents an interface to register a command executor with the proxy. */ @@ -34,8 +36,8 @@ public interface CommandManager { void unregister(String alias); /** - * Attempts to execute a command from the specified {@code cmdLine}. - * CommandExecuteEvent will not called + * Calls CommandExecuteEvent and attempts to execute a command from the specified {@code cmdLine} + * sync. * * @param source the command's source * @param cmdLine the command to run @@ -44,12 +46,32 @@ public interface CommandManager { boolean execute(CommandSource source, String cmdLine); /** - * Attempts to execute a command from the specified {@code cmdLine}. + * Attempts to execute a command from the specified {@code cmdLine} sync + * without calling CommandExecuteEvent. * * @param source the command's source * @param cmdLine the command to run - * @param callEvent will CommandExecuteEvent called or not * @return true if the command was found and executed, false if it was not */ - boolean execute(CommandSource source, String cmdLine, boolean callEvent); + boolean executeImmediately(CommandSource source, String cmdLine); + + /** + * Calls CommandExecuteEvent and attempts to execute a command from the specified {@code cmdLine} + * async. + * + * @param source the command's source + * @param cmdLine the command to run + * @return A future that will be completed with the result of the command execution + */ + CompletableFuture executeAsync(CommandSource source, String cmdLine); + + /** + * Attempts to execute a command from the specified {@code cmdLine} async + * without calling CommandExecuteEvent. + * + * @param source the command's source + * @param cmdLine the command to run + * @return A future that will be completed with the result of the command execution + */ + CompletableFuture executeImmediatelyAsync(CommandSource source, String cmdLine); } 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 93caa314b..3a8a53201 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java @@ -7,9 +7,9 @@ import com.velocitypowered.api.command.Command; import com.velocitypowered.api.command.CommandManager; import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.command.RawCommand; -import com.velocitypowered.api.event.EventManager; import com.velocitypowered.api.event.command.CommandExecuteEvent; import com.velocitypowered.api.event.command.CommandExecuteEvent.CommandResult; +import com.velocitypowered.proxy.plugin.VelocityEventManager; import java.util.Arrays; import java.util.HashMap; @@ -22,9 +22,9 @@ import java.util.concurrent.CompletableFuture; public class VelocityCommandManager implements CommandManager { private final Map commands = new HashMap<>(); - private final EventManager eventManager; + private final VelocityEventManager eventManager; - public VelocityCommandManager(EventManager eventManager) { + public VelocityCommandManager(VelocityEventManager eventManager) { this.eventManager = eventManager; } @@ -74,22 +74,21 @@ public class VelocityCommandManager implements CommandManager { Preconditions.checkNotNull(source, "invoker"); Preconditions.checkNotNull(cmdLine, "cmdLine"); - return execute(source, cmdLine, false); + CommandExecuteEvent event = callCommandEvent(source, cmdLine).join(); + CommandResult commandResult = event.getResult(); + if (commandResult.isForwardToServer() || !commandResult.isAllowed()) { + return false; + } + cmdLine = commandResult.getCommand().orElse(event.getCommand()); + + return executeImmediately(source, cmdLine); } @Override - public boolean execute(CommandSource source, String cmdLine, boolean callEvent) { + public boolean executeImmediately(CommandSource source, String cmdLine) { Preconditions.checkNotNull(source, "invoker"); Preconditions.checkNotNull(cmdLine, "cmdLine"); - if (callEvent) { - CommandExecuteEvent event = callCommandEvent(source, cmdLine).join(); - CommandResult commandResult = event.getResult(); - if (commandResult.isForwardToServer() || !commandResult.isAllowed()) { - return false; - } - cmdLine = commandResult.getCommand().orElse(event.getCommand()); - } String alias = cmdLine; String args = ""; int firstSpace = cmdLine.indexOf(' '); @@ -113,6 +112,38 @@ public class VelocityCommandManager implements CommandManager { } } + + @Override + public CompletableFuture executeAsync(CommandSource source, String cmdLine) { + CompletableFuture result = new CompletableFuture<>(); + callCommandEvent(source, cmdLine).thenAccept(event -> { + CommandResult commandResult = event.getResult(); + if (commandResult.isForwardToServer() || !commandResult.isAllowed()) { + result.complete(false); + } + String command = commandResult.getCommand().orElse(event.getCommand()); + try { + result.complete(executeImmediately(source, command)); + } catch (Exception e) { + result.completeExceptionally(e); + } + }); + return result; + } + + @Override + public CompletableFuture executeImmediatelyAsync(CommandSource source, String cmdLine) { + CompletableFuture result = new CompletableFuture<>(); + eventManager.getService().execute(() -> { + try { + result.complete(executeImmediately(source, cmdLine)); + } catch (Exception e) { + result.completeExceptionally(e); + } + }); + return result; + } + public boolean hasCommand(String command) { return commands.containsKey(command); } 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 4864bcf22..e8b747bac 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 @@ -136,7 +136,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { } if (commandResult.isAllowed()) { try { - if (!server.getCommandManager().execute(player, command)) { + if (!server.getCommandManager().executeImmediately(player, command)) { smc.write(Chat.createServerbound(command)); } } catch (Exception e) { 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 0123db3e1..1ccc0c101 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/console/VelocityConsole.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/console/VelocityConsole.java @@ -8,6 +8,8 @@ import com.velocitypowered.api.permission.Tristate; import com.velocitypowered.api.proxy.ConsoleCommandSource; import com.velocitypowered.proxy.VelocityServer; import java.util.List; +import java.util.concurrent.CompletableFuture; + import net.kyori.text.Component; import net.kyori.text.TextComponent; import net.kyori.text.format.TextColor; @@ -91,7 +93,7 @@ public final class VelocityConsole extends SimpleTerminalConsole implements Cons @Override protected void runCommand(String command) { try { - if (!this.server.getCommandManager().execute(this, command, true)) { + if (!this.server.getCommandManager().execute(this, command)) { sendMessage(TextComponent.of("Command not found.", TextColor.RED)); } } catch (Exception e) { 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 2ef08dade..87b0097b6 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/plugin/VelocityEventManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/plugin/VelocityEventManager.java @@ -185,6 +185,10 @@ public class VelocityEventManager implements EventManager { fireEvent(new ProxyShutdownEvent()); } + public ExecutorService getService() { + return service; + } + private static class VelocityMethodScanner implements MethodScanner { @Override From 26bf94f08f3c4c25304ad023392f348c1bf85170 Mon Sep 17 00:00:00 2001 From: Leymooo Date: Mon, 27 Apr 2020 13:09:04 +0300 Subject: [PATCH 11/36] fix typos, update javadocs --- .../api/command/CommandManager.java | 21 +++++++++++++------ .../event/command/CommandExecuteEvent.java | 4 ++-- .../proxy/command/VelocityCommandManager.java | 8 ++++--- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/command/CommandManager.java b/api/src/main/java/com/velocitypowered/api/command/CommandManager.java index af200cb74..f29777d6f 100644 --- a/api/src/main/java/com/velocitypowered/api/command/CommandManager.java +++ b/api/src/main/java/com/velocitypowered/api/command/CommandManager.java @@ -36,22 +36,29 @@ public interface CommandManager { void unregister(String alias); /** - * Calls CommandExecuteEvent and attempts to execute a command from the specified {@code cmdLine} - * sync. + * Calls CommandExecuteEvent and attempts to execute a command using the specified {@code cmdLine} + * in a blocking fashion. * * @param source the command's source * @param cmdLine the command to run * @return true if the command was found and executed, false if it was not + * + * @deprecated This method will block current thread during event call and command execution. + * Prefer {@link #executeAsync(CommandSource, String)} instead. */ + @Deprecated boolean execute(CommandSource source, String cmdLine); /** - * Attempts to execute a command from the specified {@code cmdLine} sync - * without calling CommandExecuteEvent. + * Attempts to execute a command using the specified {@code cmdLine} in a blocking fashion without + * calling CommandExecuteEvent. * * @param source the command's source * @param cmdLine the command to run * @return true if the command was found and executed, false if it was not + * + * @deprecated This method will block current thread during event and command execution. + * Prefer {@link #executeImmediatelyAsync(CommandSource, String)} instead. */ boolean executeImmediately(CommandSource source, String cmdLine); @@ -61,7 +68,8 @@ public interface CommandManager { * * @param source the command's source * @param cmdLine the command to run - * @return A future that will be completed with the result of the command execution + * @return A future that will be completed with the result of the command execution. + * Can be completed exceptionally if exception was thrown during execution. */ CompletableFuture executeAsync(CommandSource source, String cmdLine); @@ -71,7 +79,8 @@ public interface CommandManager { * * @param source the command's source * @param cmdLine the command to run - * @return A future that will be completed with the result of the command execution + * @return A future that will be completed with the result of the command execution. + * Can be completed exceptionally if exception was thrown during execution. */ CompletableFuture executeImmediatelyAsync(CommandSource source, String cmdLine); } diff --git a/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java b/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java index f92ed6892..054699568 100644 --- a/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java @@ -18,7 +18,7 @@ public final class CommandExecuteEvent implements ResultedEvent { private CommandResult result; /** - * Constructs a PlayerChatEvent. + * Constructs a CommandExecuteEvent. * @param commandSource the source executing the command * @param command the command being executed without first slash */ @@ -52,7 +52,7 @@ public final class CommandExecuteEvent implements ResultedEvent { @Override public String toString() { - return "PlayerCommmandEvent{" + return "CommandExecuteEvent{" + "commandSource=" + commandSource + ", command=" + command + ", result=" + result 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 3a8a53201..2b3975f1a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java @@ -64,14 +64,14 @@ public class VelocityCommandManager implements CommandManager { * @return CompletableFuture of event */ public CompletableFuture callCommandEvent(CommandSource source, String cmd) { - Preconditions.checkNotNull(source, "invoker"); + Preconditions.checkNotNull(source, "source"); Preconditions.checkNotNull(cmd, "cmd"); return eventManager.fire(new CommandExecuteEvent(source, cmd)); } @Override public boolean execute(CommandSource source, String cmdLine) { - Preconditions.checkNotNull(source, "invoker"); + Preconditions.checkNotNull(source, "source"); Preconditions.checkNotNull(cmdLine, "cmdLine"); CommandExecuteEvent event = callCommandEvent(source, cmdLine).join(); @@ -86,7 +86,7 @@ public class VelocityCommandManager implements CommandManager { @Override public boolean executeImmediately(CommandSource source, String cmdLine) { - Preconditions.checkNotNull(source, "invoker"); + Preconditions.checkNotNull(source, "source"); Preconditions.checkNotNull(cmdLine, "cmdLine"); String alias = cmdLine; @@ -133,6 +133,8 @@ public class VelocityCommandManager implements CommandManager { @Override public CompletableFuture executeImmediatelyAsync(CommandSource source, String cmdLine) { + Preconditions.checkNotNull(source, "source"); + Preconditions.checkNotNull(cmdLine, "cmdLine"); CompletableFuture result = new CompletableFuture<>(); eventManager.getService().execute(() -> { try { From 9d6689f64aefafdcbc0c96c30ec3cc93d1a77283 Mon Sep 17 00:00:00 2001 From: Leymooo Date: Mon, 27 Apr 2020 13:12:03 +0300 Subject: [PATCH 12/36] forgot annotation --- .../java/com/velocitypowered/api/command/CommandManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/api/src/main/java/com/velocitypowered/api/command/CommandManager.java b/api/src/main/java/com/velocitypowered/api/command/CommandManager.java index f29777d6f..402167151 100644 --- a/api/src/main/java/com/velocitypowered/api/command/CommandManager.java +++ b/api/src/main/java/com/velocitypowered/api/command/CommandManager.java @@ -60,6 +60,7 @@ public interface CommandManager { * @deprecated This method will block current thread during event and command execution. * Prefer {@link #executeImmediatelyAsync(CommandSource, String)} instead. */ + @Deprecated boolean executeImmediately(CommandSource source, String cmdLine); /** From 37a1a49fda5b513940c244a37984b38d619a982e Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Tue, 28 Apr 2020 14:10:54 -0400 Subject: [PATCH 13/36] Allow disabling BungeeCord plugin message channel. --- .../proxy/config/VelocityConfiguration.java | 14 ++++++++++++++ .../backend/BungeeCordMessageResponder.java | 4 ++++ 2 files changed, 18 insertions(+) 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 806ef44ce..67d9fcd7f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java @@ -402,6 +402,10 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi return pingPassthrough; } + public boolean isBungeePluginChannelEnabled() { + return advanced.isBungeePluginMessageChannel(); + } + @Override public String toString() { return MoreObjects.toStringHelper(this) @@ -654,6 +658,10 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi @ConfigKey("tcp-fast-open") private boolean tcpFastOpen = false; + @Comment("Enables BungeeCord plugin messaging channel support on Velocity.") + @ConfigKey("bungee-plugin-message-channel") + private boolean bungeePluginMessageChannel = true; + private Advanced() { } @@ -666,6 +674,7 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi this.readTimeout = toml.getLong("read-timeout", 30000L).intValue(); this.proxyProtocol = toml.getBoolean("proxy-protocol", false); this.tcpFastOpen = toml.getBoolean("tcp-fast-open", false); + this.bungeePluginMessageChannel = toml.getBoolean("bungee-plugin-message-channel", true); } } @@ -697,6 +706,10 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi return tcpFastOpen; } + public boolean isBungeePluginMessageChannel() { + return bungeePluginMessageChannel; + } + @Override public String toString() { return "Advanced{" @@ -707,6 +720,7 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi + ", readTimeout=" + readTimeout + ", proxyProtocol=" + proxyProtocol + ", tcpFastOpen=" + tcpFastOpen + + ", bungeePluginMessageChannel=" + bungeePluginMessageChannel + '}'; } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BungeeCordMessageResponder.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BungeeCordMessageResponder.java index 911e803cd..deb5b2304 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BungeeCordMessageResponder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BungeeCordMessageResponder.java @@ -273,6 +273,10 @@ class BungeeCordMessageResponder { } boolean process(PluginMessage message) { + if (!proxy.getConfiguration().isBungeePluginChannelEnabled()) { + return false; + } + if (!MODERN_CHANNEL.getId().equals(message.getChannel()) && !LEGACY_CHANNEL.getId() .equals(message.getChannel())) { return false; From aa55af8eb715ec512461e7c59cf66e36588a20dc Mon Sep 17 00:00:00 2001 From: Leymooo Date: Wed, 29 Apr 2020 22:08:59 +0300 Subject: [PATCH 14/36] fix command forwarding --- .../proxy/connection/client/ClientPlaySessionHandler.java | 4 ++-- 1 file changed, 2 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 e8b747bac..90e7ee6bb 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 @@ -131,13 +131,13 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { Optional eventCommand = event.getResult().getCommand(); String command = eventCommand.orElse(event.getCommand()); if (commandResult.isForwardToServer()) { - smc.write(Chat.createServerbound(command)); + smc.write(Chat.createServerbound("/" + command)); return; } if (commandResult.isAllowed()) { try { if (!server.getCommandManager().executeImmediately(player, command)) { - smc.write(Chat.createServerbound(command)); + smc.write(Chat.createServerbound("/" + command)); } } catch (Exception e) { logger.info("Exception occurred while running command for {}", player.getUsername(), From d096eb342992568f780ebd287b6541a411115589 Mon Sep 17 00:00:00 2001 From: Leymooo Date: Wed, 29 Apr 2020 22:15:33 +0300 Subject: [PATCH 15/36] update class javadoc --- .../velocitypowered/api/event/command/CommandExecuteEvent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java b/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java index 054699568..8181e6a3e 100644 --- a/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java @@ -9,7 +9,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** - * This event is fired when a player types in a chat message. + * This event is fired when someone executing command */ public final class CommandExecuteEvent implements ResultedEvent { From 4b4ed02e8dd4720a9f99a3f8d868b8c71af81cee Mon Sep 17 00:00:00 2001 From: Leymooo Date: Thu, 30 Apr 2020 01:00:12 +0300 Subject: [PATCH 16/36] fix build --- .../velocitypowered/api/event/command/CommandExecuteEvent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java b/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java index 8181e6a3e..d08a323f6 100644 --- a/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java @@ -9,7 +9,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** - * This event is fired when someone executing command + * This event is fired when someone executing command. */ public final class CommandExecuteEvent implements ResultedEvent { From 3bc8323ed57085814e2782d8190487bc64d13c56 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Fri, 8 May 2020 14:03:30 -0400 Subject: [PATCH 17/36] We're well into 2020, just saying. --- .../java/com/velocitypowered/proxy/command/VelocityCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommand.java b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommand.java index 1c3b777c3..ec245152e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommand.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommand.java @@ -166,7 +166,7 @@ public class VelocityCommand implements Command { .append(TextComponent.of(version.getVersion()).decoration(TextDecoration.BOLD, false)) .build(); TextComponent copyright = TextComponent - .of("Copyright 2018-2019 " + version.getVendor() + ". " + version.getName() + .of("Copyright 2018-2020 " + version.getVendor() + ". " + version.getName() + " is freely licensed under the terms of the MIT License."); source.sendMessage(velocity); source.sendMessage(copyright); From 21f03d5d504ad0e1e222acbeb311875e7857d70b Mon Sep 17 00:00:00 2001 From: Mark Vainomaa Date: Fri, 8 May 2020 03:03:49 +0300 Subject: [PATCH 18/36] Add prevent-proxy-connections option to make sending client IP to Mojang toggleable --- .../api/proxy/config/ProxyConfig.java | 9 +++++++++ .../proxy/config/VelocityConfiguration.java | 13 +++++++++++++ .../connection/client/LoginSessionHandler.java | 9 ++++++--- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/proxy/config/ProxyConfig.java b/api/src/main/java/com/velocitypowered/api/proxy/config/ProxyConfig.java index 7b4d0bae2..6e5de2371 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/config/ProxyConfig.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/config/ProxyConfig.java @@ -62,6 +62,15 @@ public interface ProxyConfig { */ boolean isOnlineMode(); + /** + * If client's ISP/AS sent from this proxy is different from the one from Mojang's + * authentication server, the player is kicked. This disallows some VPN and proxy + * connections but is a weak form of protection. + * + * @return whether to prevent client proxy connections by checking the IP with Mojang servers + */ + boolean shouldPreventClientProxyConnections(); + /** * Get a Map of all servers registered in velocity.toml. This method does * not return all the servers currently in memory, although in most cases it 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 67d9fcd7f..3b83c4380 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java @@ -54,6 +54,14 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi @ConfigKey("online-mode") private boolean onlineMode = true; + @Comment({ + "If client's ISP/AS sent from this proxy is different from the one from Mojang's", + "authentication server, the player is kicked. This disallows some VPN and proxy", + "connections but is a weak form of protection." + }) + @ConfigKey("prevent-client-proxy-connections") + private boolean preventClientProxyConnections = false; + @Comment({ "Should we forward IP addresses and other data to backend servers?", "Available options:", @@ -328,6 +336,11 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi return onlineMode; } + @Override + public boolean shouldPreventClientProxyConnections() { + return preventClientProxyConnections; + } + public PlayerInfoForwarding getPlayerInfoForwardingMode() { return playerInfoForwardingMode; } 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 6fb58ffea..e367174c9 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 @@ -50,7 +50,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler { private static final Logger logger = LogManager.getLogger(LoginSessionHandler.class); private static final String MOJANG_HASJOINED_URL = - "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=%s&serverId=%s&ip=%s"; + "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=%s&serverId=%s"; private final VelocityServer server; private final MinecraftConnection mcConnection; @@ -96,8 +96,11 @@ public class LoginSessionHandler implements MinecraftSessionHandler { String playerIp = ((InetSocketAddress) mcConnection.getRemoteAddress()).getHostString(); String url = String.format(MOJANG_HASJOINED_URL, - urlFormParameterEscaper().escape(login.getUsername()), serverId, - urlFormParameterEscaper().escape(playerIp)); + urlFormParameterEscaper().escape(login.getUsername()), serverId); + + if (server.getConfiguration().shouldPreventClientProxyConnections()) { + url += "&ip=" + urlFormParameterEscaper().escape(playerIp); + } ListenableFuture hasJoinedResponse = server.getAsyncHttpClient().prepareGet(url) .execute(); From feb7c2f893d8438449a49c7cfd25bfaa080f2832 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Fri, 8 May 2020 18:16:14 -0400 Subject: [PATCH 19/36] Reject invalid tab complete command requests. --- .../proxy/protocol/packet/TabCompleteRequest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteRequest.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteRequest.java index e382861fe..5db35433c 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteRequest.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteRequest.java @@ -78,9 +78,9 @@ public class TabCompleteRequest implements MinecraftPacket { public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { if (version.compareTo(MINECRAFT_1_13) >= 0) { this.transactionId = ProtocolUtils.readVarInt(buf); - this.command = ProtocolUtils.readString(buf); + this.command = ProtocolUtils.readString(buf, Chat.MAX_SERVERBOUND_MESSAGE_LENGTH); } else { - this.command = ProtocolUtils.readString(buf); + this.command = ProtocolUtils.readString(buf, Chat.MAX_SERVERBOUND_MESSAGE_LENGTH); if (version.compareTo(MINECRAFT_1_9) >= 0) { this.assumeCommand = buf.readBoolean(); } From 91e9769c5aab7a629c1cc7f2a3bc3f6f88ba8582 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sun, 17 May 2020 00:24:00 -0400 Subject: [PATCH 20/36] Cap /server list to 50 servers. Any more, and the server list is arguably useless. Thanks to BXBW for finding this particular issue! --- .../velocitypowered/proxy/command/ServerCommand.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) 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 b79d955bf..1e21e0ab7 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/ServerCommand.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/ServerCommand.java @@ -12,8 +12,6 @@ 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 java.util.ArrayList; -import java.util.Comparator; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -25,6 +23,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; public class ServerCommand implements Command { + public static final int MAX_SERVERS_TO_LIST = 50; private final ProxyServer server; public ServerCommand(ProxyServer server) { @@ -61,10 +60,16 @@ public class ServerCommand implements Command { executor.sendMessage(of("You are currently connected to " + currentServer + ".", TextColor.YELLOW)); + List servers = BuiltinCommandUtil.sortedServerList(server); + if (servers.size() > MAX_SERVERS_TO_LIST) { + executor.sendMessage(of("Too many servers to list. Tab-complete to show all servers.", + TextColor.RED)); + return; + } + // Assemble the list of servers as components TextComponent.Builder serverListBuilder = TextComponent.builder("Available servers: ") .color(TextColor.YELLOW); - List servers = BuiltinCommandUtil.sortedServerList(server); for (int i = 0; i < servers.size(); i++) { RegisteredServer rs = servers.get(i); serverListBuilder.append(formatServerComponent(currentServer, rs)); From fa954ab717a6c5da28c4f8034df3250576645a9e Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Mon, 25 May 2020 09:38:22 -0400 Subject: [PATCH 21/36] Confine preconnect validation/setup logic to event loop. --- .../proxy/connection/client/ConnectedPlayer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 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 fd6b9d71c..49ebc529a 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 @@ -733,7 +733,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { // Otherwise, initiate the connection. ServerPreConnectEvent event = new ServerPreConnectEvent(ConnectedPlayer.this, toConnect); return server.getEventManager().fire(event) - .thenCompose(newEvent -> { + .thenComposeAsync(newEvent -> { Optional connectTo = newEvent.getResult().getServer(); if (!connectTo.isPresent()) { return CompletableFuture.completedFuture( @@ -754,7 +754,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { server); connectionInFlight = con; return con.connect(); - }); + }, connection.eventLoop()); } @Override From b0f1398b454ef6a3ef8a1f6701373eac975f231e Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Mon, 25 May 2020 10:26:05 -0400 Subject: [PATCH 22/36] Further confinement of preconnect checks to event loop. --- .../connection/client/ConnectedPlayer.java | 67 ++++++++++--------- 1 file changed, 36 insertions(+), 31 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 49ebc529a..09bfd08e2 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 @@ -1,5 +1,8 @@ package com.velocitypowered.proxy.connection.client; +import static com.velocitypowered.proxy.connection.util.ConnectionRequestResults.plainResult; +import static java.util.concurrent.CompletableFuture.completedFuture; + import com.google.common.base.Preconditions; import com.google.gson.JsonObject; import com.velocitypowered.api.event.connection.DisconnectEvent; @@ -33,7 +36,6 @@ import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation; import com.velocitypowered.proxy.connection.backend.VelocityServerConnection; import com.velocitypowered.proxy.connection.forge.legacy.LegacyForgeConstants; import com.velocitypowered.proxy.connection.util.ConnectionMessages; -import com.velocitypowered.proxy.connection.util.ConnectionRequestResults; import com.velocitypowered.proxy.connection.util.ConnectionRequestResults.Impl; import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.packet.Chat; @@ -711,8 +713,8 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { } private Optional checkServer(RegisteredServer server) { - Preconditions - .checkState(server instanceof VelocityRegisteredServer, "Not a valid Velocity server."); + Preconditions.checkArgument(server instanceof VelocityRegisteredServer, + "Not a valid Velocity server."); if (connectionInFlight != null || (connectedServer != null && !connectedServer.hasCompletedJoin())) { return Optional.of(ConnectionRequestBuilder.Status.CONNECTION_IN_PROGRESS); @@ -723,38 +725,41 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { return Optional.empty(); } + private CompletableFuture> getInitialStatus() { + return CompletableFuture.supplyAsync(() -> checkServer(toConnect), connection.eventLoop()); + } + private CompletableFuture internalConnect() { - Optional initialCheck = checkServer(toConnect); - if (initialCheck.isPresent()) { - return CompletableFuture - .completedFuture(ConnectionRequestResults.plainResult(initialCheck.get(), toConnect)); - } - - // Otherwise, initiate the connection. - ServerPreConnectEvent event = new ServerPreConnectEvent(ConnectedPlayer.this, toConnect); - return server.getEventManager().fire(event) - .thenComposeAsync(newEvent -> { - Optional connectTo = newEvent.getResult().getServer(); - if (!connectTo.isPresent()) { - return CompletableFuture.completedFuture( - ConnectionRequestResults - .plainResult(ConnectionRequestBuilder.Status.CONNECTION_CANCELLED, toConnect) - ); + return this.getInitialStatus() + .thenCompose(initialCheck -> { + if (initialCheck.isPresent()) { + return completedFuture(plainResult(initialCheck.get(), toConnect)); } - RegisteredServer rs = connectTo.get(); - Optional lastCheck = checkServer(rs); - if (lastCheck.isPresent()) { - return CompletableFuture - .completedFuture(ConnectionRequestResults.plainResult(lastCheck.get(), rs)); - } + ServerPreConnectEvent event = new ServerPreConnectEvent(ConnectedPlayer.this, + toConnect); + return server.getEventManager().fire(event) + .thenComposeAsync(newEvent -> { + Optional newDest = newEvent.getResult().getServer(); + if (!newDest.isPresent()) { + return completedFuture( + plainResult(ConnectionRequestBuilder.Status.CONNECTION_CANCELLED, toConnect) + ); + } - VelocityRegisteredServer vrs = (VelocityRegisteredServer) rs; - VelocityServerConnection con = new VelocityServerConnection(vrs, ConnectedPlayer.this, - server); - connectionInFlight = con; - return con.connect(); - }, connection.eventLoop()); + RegisteredServer realDestination = newDest.get(); + Optional check = checkServer(realDestination); + if (check.isPresent()) { + return completedFuture(plainResult(check.get(), realDestination)); + } + + VelocityRegisteredServer vrs = (VelocityRegisteredServer) realDestination; + VelocityServerConnection con = new VelocityServerConnection(vrs, + ConnectedPlayer.this, server); + connectionInFlight = con; + return con.connect(); + }, connection.eventLoop()); + }); } @Override From 64c16e61d2f7dbe18ca60afa4650419938001e2e Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Mon, 25 May 2020 11:44:02 -0400 Subject: [PATCH 23/36] Reset in-flight connection only if the server disconnects the client. --- .../proxy/connection/client/ConnectedPlayer.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 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 09bfd08e2..19f519591 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 @@ -766,11 +766,12 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { public CompletableFuture connect() { return this.internalConnect() .whenCompleteAsync((status, throwable) -> { - if (status != null && !status.isSafe()) { - // If it's not safe to continue the connection we need to shut it down. - handleConnectionException(status.getAttemptedConnection(), throwable, true); - } else if ((status != null && !status.isSuccessful())) { - resetInFlightConnection(); + if (status != null && !status.isSuccessful()) { + if (!status.isSafe()) { + handleConnectionException(status.getAttemptedConnection(), throwable, false); + } else if (status.getStatus() == Status.SERVER_DISCONNECTED) { + resetInFlightConnection(); + } } }, connection.eventLoop()) .thenApply(x -> x); From 74ff56cbc9781851b88e1959ea93dda32a156530 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Mon, 25 May 2020 11:49:45 -0400 Subject: [PATCH 24/36] Also reset when an exception is thrown. --- .../proxy/connection/client/ConnectedPlayer.java | 2 ++ 1 file changed, 2 insertions(+) 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 19f519591..4c5954cf6 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 @@ -772,6 +772,8 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { } else if (status.getStatus() == Status.SERVER_DISCONNECTED) { resetInFlightConnection(); } + } else if (throwable != null) { + resetInFlightConnection(); } }, connection.eventLoop()) .thenApply(x -> x); From 942e2f2e1ad489561ce8ea2eb6ead5b4dea88f6b Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Mon, 25 May 2020 11:56:56 -0400 Subject: [PATCH 25/36] Better generic cleanup. --- .../proxy/connection/client/ConnectedPlayer.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 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 4c5954cf6..e646a2179 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 @@ -757,11 +757,18 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { VelocityServerConnection con = new VelocityServerConnection(vrs, ConnectedPlayer.this, server); connectionInFlight = con; - return con.connect(); + return con.connect().whenCompleteAsync((result, throwable) -> + this.cleanupIfRequired(con)); }, connection.eventLoop()); }); } + private void cleanupIfRequired(VelocityServerConnection establishedConnection) { + if (establishedConnection == connectionInFlight) { + resetInFlightConnection(); + } + } + @Override public CompletableFuture connect() { return this.internalConnect() @@ -769,11 +776,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { if (status != null && !status.isSuccessful()) { if (!status.isSafe()) { handleConnectionException(status.getAttemptedConnection(), throwable, false); - } else if (status.getStatus() == Status.SERVER_DISCONNECTED) { - resetInFlightConnection(); } - } else if (throwable != null) { - resetInFlightConnection(); } }, connection.eventLoop()) .thenApply(x -> x); From ec1fc3944ddcb5dfc14d7ba3e680cacc98ee7a18 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Mon, 25 May 2020 12:08:24 -0400 Subject: [PATCH 26/36] Make sure this runs on the event loop. --- .../proxy/connection/client/ConnectedPlayer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 e646a2179..5f550e5a0 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 @@ -758,7 +758,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { ConnectedPlayer.this, server); connectionInFlight = con; return con.connect().whenCompleteAsync((result, throwable) -> - this.cleanupIfRequired(con)); + this.cleanupIfRequired(con), connection.eventLoop()); }, connection.eventLoop()); }); } From 0cb4c021071a5545d28dbcde23c0876f84fb1590 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Mon, 25 May 2020 13:09:04 -0400 Subject: [PATCH 27/36] Run all commands on a separate thread pool. --- .../proxy/command/VelocityCommand.java | 2 - .../client/ClientPlaySessionHandler.java | 58 +++++++++++-------- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommand.java b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommand.java index ec245152e..f27b773e4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommand.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommand.java @@ -11,7 +11,6 @@ import com.velocitypowered.api.plugin.PluginDescription; import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.util.ProxyVersion; import com.velocitypowered.proxy.VelocityServer; -import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.Locale; @@ -20,7 +19,6 @@ import java.util.stream.Collectors; import net.kyori.text.TextComponent; import net.kyori.text.event.ClickEvent; import net.kyori.text.event.HoverEvent; -import net.kyori.text.event.HoverEvent.Action; import net.kyori.text.format.TextColor; import net.kyori.text.format.TextDecoration; import org.apache.logging.log4j.LogManager; 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 90e7ee6bb..930dd00df 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,7 +4,7 @@ import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_13; import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_8; import static com.velocitypowered.proxy.protocol.util.PluginMessageUtil.constructChannelsPacket; -import com.velocitypowered.api.event.command.CommandExecuteEvent; +import com.velocitypowered.api.event.command.CommandExecuteEvent.CommandResult; import com.velocitypowered.api.event.connection.PluginMessageEvent; import com.velocitypowered.api.event.player.PlayerChatEvent; import com.velocitypowered.api.event.player.PlayerResourcePackStatusEvent; @@ -42,6 +42,7 @@ import java.util.List; import java.util.Optional; import java.util.Queue; import java.util.UUID; +import java.util.concurrent.CompletableFuture; import net.kyori.text.TextComponent; import net.kyori.text.format.TextColor; import org.apache.logging.log4j.LogManager; @@ -124,30 +125,18 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { String msg = packet.getMessage(); if (msg.startsWith("/")) { - + String originalCommand = msg.substring(1); server.getCommandManager().callCommandEvent(player, msg.substring(1)) - .thenAcceptAsync(event -> { - CommandExecuteEvent.CommandResult commandResult = event.getResult(); - Optional eventCommand = event.getResult().getCommand(); - String command = eventCommand.orElse(event.getCommand()); - if (commandResult.isForwardToServer()) { - smc.write(Chat.createServerbound("/" + command)); - return; - } - if (commandResult.isAllowed()) { - try { - if (!server.getCommandManager().executeImmediately(player, command)) { - smc.write(Chat.createServerbound("/" + command)); - } - } catch (Exception e) { - logger.info("Exception occurred while running command for {}", player.getUsername(), - e); - player.sendMessage( - TextComponent.of("An error occurred while running this command.", - TextColor.RED)); - } - } - }, smc.eventLoop()); + .thenComposeAsync(event -> processCommandExecuteResult(originalCommand, + event.getResult())) + .exceptionally(e -> { + logger.info("Exception occurred while running command for {}", + player.getUsername(), e); + player.sendMessage( + TextComponent.of("An error occurred while running this command.", + TextColor.RED)); + return null; + }); } else { PlayerChatEvent event = new PlayerChatEvent(player, msg); server.getEventManager().fire(event) @@ -166,6 +155,27 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { return true; } + private CompletableFuture processCommandExecuteResult(String originalCommand, + CommandResult result) { + if (result == CommandResult.denied()) { + return CompletableFuture.completedFuture(null); + } + + MinecraftConnection smc = player.ensureAndGetCurrentServer().ensureConnected(); + String commandToRun = result.getCommand().orElse(originalCommand); + if (result.isForwardToServer()) { + return CompletableFuture.runAsync(() -> smc.write(Chat.createServerbound("/" + + commandToRun)), smc.eventLoop()); + } else { + return server.getCommandManager().executeImmediatelyAsync(player, commandToRun) + .thenAcceptAsync(hasRun -> { + if (!hasRun) { + smc.write(Chat.createServerbound("/" + commandToRun)); + } + }, smc.eventLoop()); + } + } + @Override public boolean handle(TabCompleteRequest packet) { boolean isCommand = !packet.isAssumeCommand() && packet.getCommand().startsWith("/"); From abd81a0216ec191a81f1319cbe4bc8054f64b900 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Mon, 25 May 2020 13:24:41 -0400 Subject: [PATCH 28/36] Fix Checkstyle errors. --- .../client/ClientPlaySessionHandler.java | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 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 930dd00df..3affdf9ea 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 @@ -155,27 +155,6 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { return true; } - private CompletableFuture processCommandExecuteResult(String originalCommand, - CommandResult result) { - if (result == CommandResult.denied()) { - return CompletableFuture.completedFuture(null); - } - - MinecraftConnection smc = player.ensureAndGetCurrentServer().ensureConnected(); - String commandToRun = result.getCommand().orElse(originalCommand); - if (result.isForwardToServer()) { - return CompletableFuture.runAsync(() -> smc.write(Chat.createServerbound("/" + - commandToRun)), smc.eventLoop()); - } else { - return server.getCommandManager().executeImmediatelyAsync(player, commandToRun) - .thenAcceptAsync(hasRun -> { - if (!hasRun) { - smc.write(Chat.createServerbound("/" + commandToRun)); - } - }, smc.eventLoop()); - } - } - @Override public boolean handle(TabCompleteRequest packet) { boolean isCommand = !packet.isAssumeCommand() && packet.getCommand().startsWith("/"); @@ -485,6 +464,27 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { }, player.getConnection().eventLoop()); } + private CompletableFuture processCommandExecuteResult(String originalCommand, + CommandResult result) { + if (result == CommandResult.denied()) { + return CompletableFuture.completedFuture(null); + } + + MinecraftConnection smc = player.ensureAndGetCurrentServer().ensureConnected(); + String commandToRun = result.getCommand().orElse(originalCommand); + if (result.isForwardToServer()) { + return CompletableFuture.runAsync(() -> smc.write(Chat.createServerbound("/" + + commandToRun)), smc.eventLoop()); + } else { + return server.getCommandManager().executeImmediatelyAsync(player, commandToRun) + .thenAcceptAsync(hasRun -> { + if (!hasRun) { + smc.write(Chat.createServerbound("/" + commandToRun)); + } + }, smc.eventLoop()); + } + } + /** * Immediately send any queued messages to the server. */ From d7bbe7531a89100e10e5a082b6cdc445df9edd72 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Mon, 25 May 2020 15:58:52 -0400 Subject: [PATCH 29/36] Additional protocol hardening. --- .../proxy/protocol/ProtocolUtils.java | 83 +++++++++++-------- .../protocol/netty/MinecraftDecoder.java | 6 +- .../protocol/util/NettyPreconditions.java | 26 +++++- 3 files changed, 72 insertions(+), 43 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java index 555885575..a112c9681 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java @@ -1,13 +1,16 @@ package com.velocitypowered.proxy.protocol; import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkState; +import static com.velocitypowered.proxy.protocol.util.NettyPreconditions.checkFrame; import com.google.common.base.Preconditions; import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.util.GameProfile; +import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder; +import com.velocitypowered.proxy.util.except.QuietException; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; +import io.netty.handler.codec.CorruptedFrameException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; @@ -16,6 +19,7 @@ import java.util.UUID; public enum ProtocolUtils { ; private static final int DEFAULT_MAX_STRING_SIZE = 65536; // 64KiB + private static final QuietException BAD_VARINT_CACHED = new QuietException("Bad varint decoded"); /** * Reads a Minecraft-style VarInt from the specified {@code buf}. @@ -23,13 +27,32 @@ public enum ProtocolUtils { * @return the decoded VarInt */ public static int readVarInt(ByteBuf buf) { + int read = readVarIntSafely(buf); + if (read == -1) { + throw MinecraftDecoder.DEBUG ? BAD_VARINT_CACHED + : new CorruptedFrameException("Bad varint decoded"); + } + return read; + } + + /** + * Reads a Minecraft-style VarInt from the specified {@code buf}. The difference between this + * method and {@link #readVarInt(ByteBuf)} is that this function returns a sentinel value if the + * varint is invalid. + * @param buf the buffer to read from + * @return the decoded VarInt, or {@code -1} if the varint is invalid + */ + public static int readVarIntSafely(ByteBuf buf) { int i = 0; int j = 0; while (true) { + if (!buf.isReadable()) { + return -1; + } int k = buf.readByte(); i |= (k & 0x7F) << j++ * 7; if (j > 5) { - throw new RuntimeException("VarInt too big"); + return -1; } if ((k & 0x80) != 128) { break; @@ -68,17 +91,21 @@ public enum ProtocolUtils { */ public static String readString(ByteBuf buf, int cap) { int length = readVarInt(buf); - checkArgument(length >= 0, "Got a negative-length string (%s)", length); + return readString(buf, cap, length); + } + + private static String readString(ByteBuf buf, int cap, int length) { + checkFrame(length >= 0, "Got a negative-length string (%s)", length); // `cap` is interpreted as a UTF-8 character length. To cover the full Unicode plane, we must - // consider the length of a UTF-8 character, which can be up to a 4 bytes. We do an initial + // consider the length of a UTF-8 character, which can be up to 4 bytes. We do an initial // sanity check and then check again to make sure our optimistic guess was good. - checkArgument(length <= cap * 4, "Bad string size (got %s, maximum is %s)", length, cap); - checkState(buf.isReadable(length), + checkFrame(length <= cap * 4, "Bad string size (got %s, maximum is %s)", length, cap); + checkFrame(buf.isReadable(length), "Trying to read a string that is too long (wanted %s, only have %s)", length, buf.readableBytes()); String str = buf.toString(buf.readerIndex(), length, StandardCharsets.UTF_8); buf.skipBytes(length); - checkState(str.length() <= cap, "Got a too-long string (got %s, max %s)", + checkFrame(str.length() <= cap, "Got a too-long string (got %s, max %s)", str.length(), cap); return str; } @@ -107,9 +134,9 @@ public enum ProtocolUtils { */ public static byte[] readByteArray(ByteBuf buf, int cap) { int length = readVarInt(buf); - checkArgument(length >= 0, "Got a negative-length array (%s)", length); - checkArgument(length <= cap, "Bad array size (got %s, maximum is %s)", length, cap); - checkState(buf.isReadable(length), + checkFrame(length >= 0, "Got a negative-length array (%s)", length); + checkFrame(length <= cap, "Bad array size (got %s, maximum is %s)", length, cap); + checkFrame(buf.isReadable(length), "Trying to read an array that is too long (wanted %s, only have %s)", length, buf.readableBytes()); byte[] array = new byte[length]; @@ -228,7 +255,7 @@ public enum ProtocolUtils { // No vanilla packet should give a 3 byte packet int len = readExtendedForgeShort(buf); - Preconditions.checkArgument(len <= (FORGE_MAX_ARRAY_LENGTH), + checkFrame(len <= (FORGE_MAX_ARRAY_LENGTH), "Cannot receive array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, len); return buf.readRetainedSlice(len); @@ -243,12 +270,11 @@ public enum ProtocolUtils { */ public static void writeByteArray17(byte[] b, ByteBuf buf, boolean allowExtended) { if (allowExtended) { - Preconditions - .checkArgument(b.length <= (FORGE_MAX_ARRAY_LENGTH), - "Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, - b.length); + checkFrame(b.length <= (FORGE_MAX_ARRAY_LENGTH), + "Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, + b.length); } else { - Preconditions.checkArgument(b.length <= Short.MAX_VALUE, + checkFrame(b.length <= Short.MAX_VALUE, "Cannot send array longer than Short.MAX_VALUE (got %s bytes)", b.length); } // Write a 2 or 3 byte number that represents the length of the packet. (3 byte "shorts" for @@ -268,12 +294,11 @@ public enum ProtocolUtils { */ public static void writeByteBuf17(ByteBuf b, ByteBuf buf, boolean allowExtended) { if (allowExtended) { - Preconditions - .checkArgument(b.readableBytes() <= (FORGE_MAX_ARRAY_LENGTH), - "Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, - b.readableBytes()); + checkFrame(b.readableBytes() <= (FORGE_MAX_ARRAY_LENGTH), + "Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, + b.readableBytes()); } else { - Preconditions.checkArgument(b.readableBytes() <= Short.MAX_VALUE, + checkFrame(b.readableBytes() <= Short.MAX_VALUE, "Cannot send array longer than Short.MAX_VALUE (got %s bytes)", b.readableBytes()); } // Write a 2 or 3 byte number that represents the length of the packet. (3 byte "shorts" for @@ -326,21 +351,7 @@ public enum ProtocolUtils { * @return the decoded string */ public static String readStringWithoutLength(ByteBuf buf) { - int length = buf.readableBytes(); - int cap = DEFAULT_MAX_STRING_SIZE; - checkArgument(length >= 0, "Got a negative-length string (%s)", length); - // `cap` is interpreted as a UTF-8 character length. To cover the full Unicode plane, we must - // consider the length of a UTF-8 character, which can be up to a 4 bytes. We do an initial - // sanity check and then check again to make sure our optimistic guess was good. - checkArgument(length <= cap * 4, "Bad string size (got %s, maximum is %s)", length, cap); - checkState(buf.isReadable(length), - "Trying to read a string that is too long (wanted %s, only have %s)", length, - buf.readableBytes()); - String str = buf.toString(buf.readerIndex(), length, StandardCharsets.UTF_8); - buf.skipBytes(length); - checkState(str.length() <= cap, "Got a too-long string (got %s, max %s)", - str.length(), cap); - return str; + return readString(buf, DEFAULT_MAX_STRING_SIZE, buf.readableBytes()); } public enum Direction { 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 0204aefb3..c37fef224 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 @@ -14,7 +14,7 @@ import java.util.List; public class MinecraftDecoder extends MessageToMessageDecoder { - private static final boolean DEBUG = Boolean.getBoolean("velocity.packet-decode-logging"); + public static final boolean DEBUG = Boolean.getBoolean("velocity.packet-decode-logging"); private static final QuietException DECODE_FAILED = new QuietException("A packet did not decode successfully (invalid data). If you are a " + "developer, launch Velocity with -Dvelocity.packet-decode-logging=true to see more."); @@ -30,8 +30,8 @@ public class MinecraftDecoder extends MessageToMessageDecoder { */ public MinecraftDecoder(ProtocolUtils.Direction direction) { this.direction = Preconditions.checkNotNull(direction, "direction"); - this.registry = direction - .getProtocolRegistry(StateRegistry.HANDSHAKE, ProtocolVersion.MINIMUM_VERSION); + this.registry = direction.getProtocolRegistry(StateRegistry.HANDSHAKE, + ProtocolVersion.MINIMUM_VERSION); this.state = StateRegistry.HANDSHAKE; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/util/NettyPreconditions.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/util/NettyPreconditions.java index 5c5cabde1..cd3d46452 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/util/NettyPreconditions.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/util/NettyPreconditions.java @@ -1,12 +1,18 @@ package com.velocitypowered.proxy.protocol.util; import com.google.common.base.Strings; +import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder; +import com.velocitypowered.proxy.util.except.QuietException; import io.netty.handler.codec.CorruptedFrameException; /** * Extends {@link com.google.common.base.Preconditions} for Netty's {@link CorruptedFrameException}. */ public class NettyPreconditions { + private static final QuietException BAD = new QuietException( + "Invalid packet received. Launch Velocity with -Dvelocity.packet-decode-logging=true " + + "to see more."); + private NettyPreconditions() { throw new AssertionError(); } @@ -18,7 +24,7 @@ public class NettyPreconditions { */ public static void checkFrame(boolean b, String message) { if (!b) { - throw new CorruptedFrameException(message); + throw MinecraftDecoder.DEBUG ? new CorruptedFrameException(message) : BAD; } } @@ -32,7 +38,11 @@ public class NettyPreconditions { */ public static void checkFrame(boolean b, String message, Object arg1) { if (!b) { - throw new CorruptedFrameException(Strings.lenientFormat(message, arg1)); + if (MinecraftDecoder.DEBUG) { + throw new CorruptedFrameException(Strings.lenientFormat(message, arg1)); + } else { + throw BAD; + } } } @@ -47,7 +57,11 @@ public class NettyPreconditions { */ public static void checkFrame(boolean b, String message, Object arg1, Object arg2) { if (!b) { - throw new CorruptedFrameException(Strings.lenientFormat(message, arg1, arg2)); + if (MinecraftDecoder.DEBUG) { + throw new CorruptedFrameException(Strings.lenientFormat(message, arg1, arg2)); + } else { + throw BAD; + } } } @@ -61,7 +75,11 @@ public class NettyPreconditions { */ public static void checkFrame(boolean b, String message, Object... args) { if (!b) { - throw new CorruptedFrameException(Strings.lenientFormat(message, args)); + if (MinecraftDecoder.DEBUG) { + throw new CorruptedFrameException(Strings.lenientFormat(message, args)); + } else { + throw BAD; + } } } } From ebad3d1005bfba1dc0e9262ddd1fb79a095a03c9 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Mon, 25 May 2020 16:05:36 -0400 Subject: [PATCH 30/36] Use Integer.MIN_VALUE for the sentinel for readVarIntSafely() --- .../com/velocitypowered/proxy/protocol/ProtocolUtils.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java index a112c9681..5c602014f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java @@ -28,7 +28,7 @@ public enum ProtocolUtils { */ public static int readVarInt(ByteBuf buf) { int read = readVarIntSafely(buf); - if (read == -1) { + if (read == Integer.MIN_VALUE) { throw MinecraftDecoder.DEBUG ? BAD_VARINT_CACHED : new CorruptedFrameException("Bad varint decoded"); } @@ -40,19 +40,19 @@ public enum ProtocolUtils { * method and {@link #readVarInt(ByteBuf)} is that this function returns a sentinel value if the * varint is invalid. * @param buf the buffer to read from - * @return the decoded VarInt, or {@code -1} if the varint is invalid + * @return the decoded VarInt, or {@code Integer.MIN_VALUE} if the varint is invalid */ public static int readVarIntSafely(ByteBuf buf) { int i = 0; int j = 0; while (true) { if (!buf.isReadable()) { - return -1; + return Integer.MIN_VALUE; } int k = buf.readByte(); i |= (k & 0x7F) << j++ * 7; if (j > 5) { - return -1; + return Integer.MIN_VALUE; } if ((k & 0x80) != 128) { break; From d538516f4c014a431783da110e2a88290341d45f Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Mon, 25 May 2020 16:08:53 -0400 Subject: [PATCH 31/36] Bump Netty version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d3d19cdc9..8cb7655e4 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ allprojects { junitVersion = '5.3.0-M1' slf4jVersion = '1.7.25' log4jVersion = '2.11.2' - nettyVersion = '4.1.49.Final' + nettyVersion = '4.1.50.Final' guavaVersion = '25.1-jre' checkerFrameworkVersion = '2.7.0' configurateVersion = '3.6' From eeb660ce007ee116264656b7fd8dedcbc84a97b3 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Tue, 26 May 2020 05:25:03 -0400 Subject: [PATCH 32/36] Fix bad ordering --- .../com/velocitypowered/proxy/protocol/ProtocolUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java index 5c602014f..b4e56044a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java @@ -29,8 +29,8 @@ public enum ProtocolUtils { public static int readVarInt(ByteBuf buf) { int read = readVarIntSafely(buf); if (read == Integer.MIN_VALUE) { - throw MinecraftDecoder.DEBUG ? BAD_VARINT_CACHED - : new CorruptedFrameException("Bad varint decoded"); + throw MinecraftDecoder.DEBUG ? new CorruptedFrameException("Bad varint decoded") + : BAD_VARINT_CACHED; } return read; } From 305949487e70cbaa65231ac47842f97f8dc2f061 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Thu, 28 May 2020 07:05:19 -0400 Subject: [PATCH 33/36] Add @UnstableApi annotation. Resolves #313 --- .../api/annotations/UnstableApi.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 api/src/main/java/com/velocitypowered/api/annotations/UnstableApi.java diff --git a/api/src/main/java/com/velocitypowered/api/annotations/UnstableApi.java b/api/src/main/java/com/velocitypowered/api/annotations/UnstableApi.java new file mode 100644 index 000000000..7d2859a77 --- /dev/null +++ b/api/src/main/java/com/velocitypowered/api/annotations/UnstableApi.java @@ -0,0 +1,14 @@ +package com.velocitypowered.api.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +/** + * Marks unstable API interfaces that are still maturing. These interfaces may change drastically + * between minor releases of Velocity, and it is not guaranteed that the APIs marked with this + * annotation will be stable over time. + */ +@Target({ ElementType.METHOD, ElementType.TYPE, ElementType.PACKAGE }) +public @interface UnstableApi { + +} From cb99b184ede1f452ec820c48e6601d3458d86572 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Thu, 28 May 2020 07:14:49 -0400 Subject: [PATCH 34/36] Allow plugins to mutate available commands sent to the client. This is the first unstable API being introduced and is primarily to get feedback on the system. --- api/build.gradle | 1 + .../command/PlayerAvailableCommandsEvent.java | 37 +++++++++++++++++++ .../backend/BackendPlaySessionHandler.java | 7 +++- 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 api/src/main/java/com/velocitypowered/api/event/command/PlayerAvailableCommandsEvent.java diff --git a/api/build.gradle b/api/build.gradle index b156d61fc..2680d18ce 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -26,6 +26,7 @@ dependencies { compile "org.slf4j:slf4j-api:${slf4jVersion}" compile 'com.google.inject:guice:4.2.2' compile "org.checkerframework:checker-qual:${checkerFrameworkVersion}" + compile 'com.mojang:brigadier:1.0.17' compile "org.spongepowered:configurate-hocon:${configurateVersion}" compile "org.spongepowered:configurate-yaml:${configurateVersion}" diff --git a/api/src/main/java/com/velocitypowered/api/event/command/PlayerAvailableCommandsEvent.java b/api/src/main/java/com/velocitypowered/api/event/command/PlayerAvailableCommandsEvent.java new file mode 100644 index 000000000..c60528c4c --- /dev/null +++ b/api/src/main/java/com/velocitypowered/api/event/command/PlayerAvailableCommandsEvent.java @@ -0,0 +1,37 @@ +package com.velocitypowered.api.event.command; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.mojang.brigadier.tree.RootCommandNode; +import com.velocitypowered.api.annotations.UnstableApi; +import com.velocitypowered.api.proxy.Player; + +/** + * Allows plugins to modify the packet indicating commands available on the server to a + * Minecraft 1.13+ client. + */ +@UnstableApi +public class PlayerAvailableCommandsEvent { + + private final Player player; + private final RootCommandNode rootNode; + + /** + * Constructs an available commands event. + * @param player the targeted player + * @param rootNode the Brigadier root node + */ + public PlayerAvailableCommandsEvent(Player player, + RootCommandNode rootNode) { + this.player = checkNotNull(player, "player"); + this.rootNode = checkNotNull(rootNode, "rootNode"); + } + + public Player getPlayer() { + return player; + } + + public RootCommandNode getRootNode() { + return rootNode; + } +} 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 747006dce..7bde50a23 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 @@ -7,6 +7,7 @@ import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.mojang.brigadier.tree.LiteralCommandNode; +import com.velocitypowered.api.event.command.PlayerAvailableCommandsEvent; import com.velocitypowered.api.event.connection.PluginMessageEvent; import com.velocitypowered.api.proxy.messages.ChannelIdentifier; import com.velocitypowered.proxy.VelocityServer; @@ -175,7 +176,11 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { .build(); commands.getRootNode().addChild(root); } - return false; + + server.getEventManager().fire( + new PlayerAvailableCommandsEvent(serverConn.getPlayer(), commands.getRootNode())) + .thenAcceptAsync(event -> playerConnection.write(commands), playerConnection.eventLoop()); + return true; } @Override From b028d9ca8f19fd73e5b66c0d204bc289eecec5f4 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Thu, 28 May 2020 10:44:42 -0400 Subject: [PATCH 35/36] Use standard Guava annotation --- .../api/annotations/UnstableApi.java | 14 -------------- .../command/PlayerAvailableCommandsEvent.java | 4 ++-- 2 files changed, 2 insertions(+), 16 deletions(-) delete mode 100644 api/src/main/java/com/velocitypowered/api/annotations/UnstableApi.java diff --git a/api/src/main/java/com/velocitypowered/api/annotations/UnstableApi.java b/api/src/main/java/com/velocitypowered/api/annotations/UnstableApi.java deleted file mode 100644 index 7d2859a77..000000000 --- a/api/src/main/java/com/velocitypowered/api/annotations/UnstableApi.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.velocitypowered.api.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Target; - -/** - * Marks unstable API interfaces that are still maturing. These interfaces may change drastically - * between minor releases of Velocity, and it is not guaranteed that the APIs marked with this - * annotation will be stable over time. - */ -@Target({ ElementType.METHOD, ElementType.TYPE, ElementType.PACKAGE }) -public @interface UnstableApi { - -} diff --git a/api/src/main/java/com/velocitypowered/api/event/command/PlayerAvailableCommandsEvent.java b/api/src/main/java/com/velocitypowered/api/event/command/PlayerAvailableCommandsEvent.java index c60528c4c..ef9939fbc 100644 --- a/api/src/main/java/com/velocitypowered/api/event/command/PlayerAvailableCommandsEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/command/PlayerAvailableCommandsEvent.java @@ -2,15 +2,15 @@ package com.velocitypowered.api.event.command; import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.annotations.Beta; import com.mojang.brigadier.tree.RootCommandNode; -import com.velocitypowered.api.annotations.UnstableApi; import com.velocitypowered.api.proxy.Player; /** * Allows plugins to modify the packet indicating commands available on the server to a * Minecraft 1.13+ client. */ -@UnstableApi +@Beta public class PlayerAvailableCommandsEvent { private final Player player; From e83662e8c37be54e6412db70075e78764adbfaab Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Fri, 29 May 2020 21:36:58 -0400 Subject: [PATCH 36/36] Clean up imports and remove some legacy declarations. --- .../com/velocitypowered/proxy/Metrics.java | 1 - .../proxy/command/GlistCommand.java | 2 -- .../proxy/command/ShutdownCommand.java | 2 -- .../proxy/command/VelocityCommandManager.java | 1 - .../backend/VelocityServerConnection.java | 18 ------------------ .../connection/client/LoginSessionHandler.java | 2 -- .../client/StatusSessionHandler.java | 1 - .../util/ConnectionRequestResults.java | 1 - .../proxy/console/VelocityConsole.java | 2 -- .../proxy/network/ConnectionManager.java | 1 - .../proxy/network/Connections.java | 3 --- .../proxy/plugin/VelocityPluginManager.java | 1 - .../proxy/plugin/loader/PluginLoader.java | 1 - .../proxy/protocol/netty/GS4QueryHandler.java | 2 -- .../packet/brigadier/DummyProperty.java | 1 - .../proxy/server/VelocityRegisteredServer.java | 2 -- .../proxy/tablist/VelocityTabList.java | 1 - .../proxy/tablist/VelocityTabListLegacy.java | 2 -- .../proxy/util/VelocityChannelRegistrar.java | 2 -- .../proxy/util/collect/CappedSet.java | 1 - 20 files changed, 47 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/Metrics.java b/proxy/src/main/java/com/velocitypowered/proxy/Metrics.java index 2ac4f983c..955640e86 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/Metrics.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/Metrics.java @@ -9,7 +9,6 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; -import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/GlistCommand.java b/proxy/src/main/java/com/velocitypowered/proxy/command/GlistCommand.java index 2c7ddf9a6..3208dc837 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/GlistCommand.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/GlistCommand.java @@ -7,10 +7,8 @@ import com.velocitypowered.api.permission.Tristate; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.server.RegisteredServer; -import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; import net.kyori.text.TextComponent; import net.kyori.text.format.TextColor; import org.checkerframework.checker.nullness.qual.NonNull; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/ShutdownCommand.java b/proxy/src/main/java/com/velocitypowered/proxy/command/ShutdownCommand.java index 87f53b211..568c4fdf4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/ShutdownCommand.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/ShutdownCommand.java @@ -3,8 +3,6 @@ package com.velocitypowered.proxy.command; import com.velocitypowered.api.command.Command; import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.proxy.VelocityServer; -import net.kyori.text.TextComponent; -import net.kyori.text.format.TextColor; import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import org.checkerframework.checker.nullness.qual.NonNull; 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 2b3975f1a..9a90c2841 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java @@ -10,7 +10,6 @@ import com.velocitypowered.api.command.RawCommand; import com.velocitypowered.api.event.command.CommandExecuteEvent; import com.velocitypowered.api.event.command.CommandExecuteEvent.CommandResult; import com.velocitypowered.proxy.plugin.VelocityEventManager; - import java.util.Arrays; import java.util.HashMap; import java.util.List; 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 b91522507..8d0b72455 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 @@ -2,15 +2,7 @@ package com.velocitypowered.proxy.connection.backend; import static com.velocitypowered.proxy.VelocityServer.GSON; import static com.velocitypowered.proxy.connection.forge.legacy.LegacyForgeConstants.HANDSHAKE_HOSTNAME_TOKEN; -import static com.velocitypowered.proxy.network.Connections.FLOW_HANDLER; -import static com.velocitypowered.proxy.network.Connections.FLUSH_CONSOLIDATION; -import static com.velocitypowered.proxy.network.Connections.FLUSH_CONSOLIDATION_AMOUNT; -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 com.google.common.base.Preconditions; import com.velocitypowered.api.network.ProtocolVersion; @@ -24,25 +16,15 @@ import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.connection.util.ConnectionRequestResults.Impl; -import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.StateRegistry; -import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder; -import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder; -import com.velocitypowered.proxy.protocol.netty.MinecraftVarintFrameDecoder; -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.server.VelocityRegisteredServer; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; import io.netty.channel.ChannelFutureListener; -import io.netty.channel.ChannelInitializer; -import io.netty.handler.flow.FlowControlHandler; -import io.netty.handler.timeout.ReadTimeoutHandler; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; import org.checkerframework.checker.nullness.qual.Nullable; public class VelocityServerConnection implements MinecraftConnectionAssociation, ServerConnection { 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 e367174c9..380fd9831 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 @@ -6,7 +6,6 @@ import static com.velocitypowered.proxy.VelocityServer.GSON; import static com.velocitypowered.proxy.connection.VelocityConstants.EMPTY_BYTE_ARRAY; import static com.velocitypowered.proxy.util.EncryptionUtils.decryptRsa; import static com.velocitypowered.proxy.util.EncryptionUtils.generateServerId; -import static org.asynchttpclient.Dsl.asyncHttpClient; import com.google.common.base.Preconditions; import com.velocitypowered.api.event.connection.LoginEvent; @@ -21,7 +20,6 @@ import com.velocitypowered.api.util.GameProfile; import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; - import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.packet.Disconnect; import com.velocitypowered.proxy.protocol.packet.EncryptionRequest; 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 5fbbac0de..44ac9c2a5 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 @@ -22,7 +22,6 @@ import com.velocitypowered.proxy.server.VelocityRegisteredServer; import io.netty.buffer.ByteBuf; import java.net.InetSocketAddress; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/util/ConnectionRequestResults.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/util/ConnectionRequestResults.java index 2c3061ad1..b78728ff3 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/util/ConnectionRequestResults.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/util/ConnectionRequestResults.java @@ -1,7 +1,6 @@ package com.velocitypowered.proxy.connection.util; import com.velocitypowered.api.proxy.ConnectionRequestBuilder; -import com.velocitypowered.api.proxy.ConnectionRequestBuilder.Result; import com.velocitypowered.api.proxy.ConnectionRequestBuilder.Status; import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.proxy.protocol.packet.Disconnect; 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 1ccc0c101..4b9d38aee 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/console/VelocityConsole.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/console/VelocityConsole.java @@ -8,8 +8,6 @@ import com.velocitypowered.api.permission.Tristate; import com.velocitypowered.api.proxy.ConsoleCommandSource; import com.velocitypowered.proxy.VelocityServer; import java.util.List; -import java.util.concurrent.CompletableFuture; - import net.kyori.text.Component; import net.kyori.text.TextComponent; import net.kyori.text.format.TextColor; 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 649830544..0f89109df 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java @@ -18,7 +18,6 @@ import io.netty.channel.WriteBufferWaterMark; import io.netty.channel.epoll.EpollChannelOption; import io.netty.resolver.dns.DnsAddressResolverGroup; import io.netty.resolver.dns.DnsNameResolverBuilder; -import io.netty.util.concurrent.EventExecutor; import java.net.InetSocketAddress; import java.util.HashMap; import java.util.Map; 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 a0e124003..33112a089 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java @@ -15,9 +15,6 @@ public class Connections { public static final String MINECRAFT_DECODER = "minecraft-decoder"; public static final String MINECRAFT_ENCODER = "minecraft-encoder"; public static final String READ_TIMEOUT = "read-timeout"; - public static final String FLUSH_CONSOLIDATION = "flush-consolidation"; - - public static final int FLUSH_CONSOLIDATION_AMOUNT = 10; private Connections() { throw new AssertionError(); 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 b1a0c3aaa..f3931569a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/plugin/VelocityPluginManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/plugin/VelocityPluginManager.java @@ -16,7 +16,6 @@ import com.velocitypowered.api.plugin.meta.PluginDependency; import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.plugin.loader.VelocityPluginContainer; -import com.velocitypowered.proxy.plugin.loader.VelocityPluginDescription; import com.velocitypowered.proxy.plugin.loader.java.JavaPluginLoader; import com.velocitypowered.proxy.plugin.util.PluginDependencyUtils; import java.io.IOException; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/plugin/loader/PluginLoader.java b/proxy/src/main/java/com/velocitypowered/proxy/plugin/loader/PluginLoader.java index 3ffdeb4b4..560f177ec 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/plugin/loader/PluginLoader.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/plugin/loader/PluginLoader.java @@ -3,7 +3,6 @@ package com.velocitypowered.proxy.plugin.loader; import com.google.inject.Module; import com.velocitypowered.api.plugin.PluginContainer; import com.velocitypowered.api.plugin.PluginDescription; - import java.nio.file.Path; /** 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 b3407c980..9be2eae8f 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 @@ -24,8 +24,6 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import net.kyori.text.serializer.plain.PlainComponentSerializer; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/DummyProperty.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/DummyProperty.java index 9b514f903..40ac9fd5c 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/DummyProperty.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/DummyProperty.java @@ -2,7 +2,6 @@ package com.velocitypowered.proxy.protocol.packet.brigadier; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.arguments.ArgumentType; -import com.mojang.brigadier.exceptions.CommandSyntaxException; import org.checkerframework.checker.nullness.qual.Nullable; class DummyProperty implements ArgumentType { 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 dc8f1687d..979dca88f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java @@ -11,7 +11,6 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.velocitypowered.api.network.ProtocolVersion; 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; @@ -25,7 +24,6 @@ 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.packet.PluginMessage; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabList.java b/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabList.java index 09d8c01d5..6830382f6 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabList.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabList.java @@ -7,7 +7,6 @@ import com.velocitypowered.api.util.GameProfile; import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.protocol.packet.HeaderAndFooter; import com.velocitypowered.proxy.protocol.packet.PlayerListItem; -import com.velocitypowered.proxy.protocol.packet.PlayerListItem.Item; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabListLegacy.java b/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabListLegacy.java index 8e5eecf43..e46fa4820 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabListLegacy.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabListLegacy.java @@ -12,8 +12,6 @@ import java.util.Optional; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import net.kyori.text.Component; -import net.kyori.text.serializer.legacy.LegacyComponentSerializer; -import net.kyori.text.serializer.plain.PlainComponentSerializer; import org.checkerframework.checker.nullness.qual.Nullable; public class VelocityTabListLegacy extends VelocityTabList { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/util/VelocityChannelRegistrar.java b/proxy/src/main/java/com/velocitypowered/proxy/util/VelocityChannelRegistrar.java index f955fa33f..bb7c383bf 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/util/VelocityChannelRegistrar.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/util/VelocityChannelRegistrar.java @@ -6,13 +6,11 @@ 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 com.velocitypowered.proxy.protocol.util.PluginMessageUtil; import java.util.Collection; import java.util.HashSet; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; - import org.checkerframework.checker.nullness.qual.Nullable; public class VelocityChannelRegistrar implements ChannelRegistrar { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/util/collect/CappedSet.java b/proxy/src/main/java/com/velocitypowered/proxy/util/collect/CappedSet.java index a0f775f9e..334670bfd 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/util/collect/CappedSet.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/util/collect/CappedSet.java @@ -2,7 +2,6 @@ package com.velocitypowered.proxy.util.collect; import com.google.common.base.Preconditions; import com.google.common.collect.ForwardingSet; - import java.util.Collection; import java.util.HashSet; import java.util.Set;