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 78a44a68b..b473e8712 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) @@ -481,6 +470,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. */ 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..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 @@ -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,49 +725,58 @@ 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)); + return this.getInitialStatus() + .thenCompose(initialCheck -> { + if (initialCheck.isPresent()) { + return completedFuture(plainResult(initialCheck.get(), toConnect)); + } + + 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) + ); + } + + 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().whenCompleteAsync((result, throwable) -> + this.cleanupIfRequired(con), connection.eventLoop()); + }, connection.eventLoop()); + }); + } + + private void cleanupIfRequired(VelocityServerConnection establishedConnection) { + if (establishedConnection == connectionInFlight) { + resetInFlightConnection(); } - - // 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) - ); - } - - RegisteredServer rs = connectTo.get(); - Optional lastCheck = checkServer(rs); - if (lastCheck.isPresent()) { - return CompletableFuture - .completedFuture(ConnectionRequestResults.plainResult(lastCheck.get(), rs)); - } - - VelocityRegisteredServer vrs = (VelocityRegisteredServer) rs; - VelocityServerConnection con = new VelocityServerConnection(vrs, ConnectedPlayer.this, - server); - connectionInFlight = con; - return con.connect(); - }, connection.eventLoop()); } @Override 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); + } } }, connection.eventLoop()) .thenApply(x -> x);