diff --git a/api/src/main/java/com/velocitypowered/api/event/connection/DisconnectEvent.java b/api/src/main/java/com/velocitypowered/api/event/connection/DisconnectEvent.java index 2442077a8..77377e5c4 100644 --- a/api/src/main/java/com/velocitypowered/api/event/connection/DisconnectEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/connection/DisconnectEvent.java @@ -1,5 +1,9 @@ package com.velocitypowered.api.event.connection; +import static com.velocitypowered.api.event.connection.DisconnectEvent.LoginStatus.CANCELLED_BY_PROXY; +import static com.velocitypowered.api.event.connection.DisconnectEvent.LoginStatus.CONFLICTING_LOGIN; +import static com.velocitypowered.api.event.connection.DisconnectEvent.LoginStatus.SUCCESSFUL_LOGIN; + import com.google.common.base.Preconditions; import com.velocitypowered.api.proxy.Player; @@ -10,31 +14,50 @@ import com.velocitypowered.api.proxy.Player; public final class DisconnectEvent { private final Player player; - private final boolean disconnectedDuringLogin; + private final LoginStatus loginStatus; + @Deprecated public DisconnectEvent(Player player) { this(player, false); } + @Deprecated public DisconnectEvent(Player player, boolean disconnectedDuringLogin) { + this(player, disconnectedDuringLogin ? CANCELLED_BY_PROXY : SUCCESSFUL_LOGIN); + } + + public DisconnectEvent(Player player, LoginStatus loginStatus) { this.player = Preconditions.checkNotNull(player, "player"); - this.disconnectedDuringLogin = disconnectedDuringLogin; + this.loginStatus = Preconditions.checkNotNull(loginStatus, "loginStatus"); } public Player getPlayer() { return player; } + @Deprecated public boolean disconnectedDuringLogin() { - return this.disconnectedDuringLogin; + return this.loginStatus == CANCELLED_BY_PROXY || this.loginStatus == CONFLICTING_LOGIN; + } + + public LoginStatus getLoginStatus() { + return loginStatus; } @Override public String toString() { return "DisconnectEvent{" + "player=" + player + ", " - + "disconnectedDuringLogin=" + disconnectedDuringLogin + + "loginStatus=" + loginStatus + '}'; } + + public enum LoginStatus { + + SUCCESSFUL_LOGIN, + CONFLICTING_LOGIN, + CANCELLED_BY_USER, + CANCELLED_BY_PROXY + } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java index ecf8c87c3..8966e8bc4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -271,6 +271,10 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter { return channel.config().isAutoRead(); } + public boolean isKnownDisconnect() { + return knownDisconnect; + } + /** * Determines whether or not the channel should continue reading data automaticaly. * @param autoReading whether or not we should read data automatically 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 27ba08d0c..86a2ce5ac 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 @@ -6,6 +6,7 @@ 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; +import com.velocitypowered.api.event.connection.DisconnectEvent.LoginStatus; import com.velocitypowered.api.event.player.KickedFromServerEvent; import com.velocitypowered.api.event.player.KickedFromServerEvent.DisconnectPlayer; import com.velocitypowered.api.event.player.KickedFromServerEvent.Notify; @@ -586,10 +587,21 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { if (connectedServer != null) { connectedServer.disconnect(); } - boolean isConnected = server.getPlayer(this.getUniqueId()).isPresent(); + + Optional connectedPlayer = server.getPlayer(this.getUniqueId()); server.unregisterConnection(this); - server.getEventManager().fire(new DisconnectEvent(this, !isConnected)) - .thenRun(() -> this.teardownFuture.complete(null)); + + DisconnectEvent.LoginStatus status; + if (connectedPlayer.isPresent()) { + status = connectedPlayer.get() == this ? LoginStatus.SUCCESSFUL_LOGIN + : LoginStatus.CONFLICTING_LOGIN; + } else { + status = connection.isKnownDisconnect() ? LoginStatus.CANCELLED_BY_PROXY : + LoginStatus.CANCELLED_BY_USER; + } + + DisconnectEvent event = new DisconnectEvent(this, status); + server.getEventManager().fire(event).thenRun(() -> this.teardownFuture.complete(null)); } public CompletableFuture getTeardownFuture() { 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 2f185652b..7483bb076 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 @@ -202,10 +202,14 @@ public class LoginSessionHandler implements MinecraftSessionHandler { onlineMode); server.getEventManager().fire(profileRequestEvent).thenCompose(profileEvent -> { + if (mcConnection.isClosed()) { + // The player disconnected after we authenticated them. + return CompletableFuture.completedFuture(null); + } + // Initiate a regular connection and move over to it. ConnectedPlayer player = new ConnectedPlayer(server, profileEvent.getGameProfile(), - mcConnection, - inbound.getVirtualHost().orElse(null), onlineMode); + mcConnection, inbound.getVirtualHost().orElse(null), onlineMode); this.connectedPlayer = player; if (!server.canRegisterConnection(player)) { player.disconnect0(VelocityMessages.ALREADY_CONNECTED, true);