From 6775b8080e561a0e5d541accc03137fdcda92503 Mon Sep 17 00:00:00 2001 From: Adrian3d04 Date: Sat, 13 Aug 2022 21:03:34 +0000 Subject: [PATCH] feat: Improved server connection selection Now the selection mode of the server to send the player to is configurable resolves #40 --- .../configuration/ProxyConfiguration.java | 32 ++++++++++ .../authmevelocity/common/enums/SendMode.java | 7 +++ .../velocity/listener/ConnectListener.java | 19 ++---- .../listener/PluginMessageListener.java | 54 +++++++++-------- .../velocity/utils/AuthmeUtils.java | 58 +++++++++++++++++++ .../authmevelocity/velocity/utils/Pair.java | 15 +++++ 6 files changed, 144 insertions(+), 41 deletions(-) create mode 100644 common/src/main/java/me/adrianed/authmevelocity/common/enums/SendMode.java create mode 100644 velocity/src/main/java/me/adrianed/authmevelocity/velocity/utils/Pair.java diff --git a/common/src/main/java/me/adrianed/authmevelocity/common/configuration/ProxyConfiguration.java b/common/src/main/java/me/adrianed/authmevelocity/common/configuration/ProxyConfiguration.java index fdba18d..ce50144 100644 --- a/common/src/main/java/me/adrianed/authmevelocity/common/configuration/ProxyConfiguration.java +++ b/common/src/main/java/me/adrianed/authmevelocity/common/configuration/ProxyConfiguration.java @@ -3,6 +3,8 @@ package me.adrianed.authmevelocity.common.configuration; import org.spongepowered.configurate.objectmapping.ConfigSerializable; import org.spongepowered.configurate.objectmapping.meta.Comment; +import me.adrianed.authmevelocity.common.enums.SendMode; + import java.util.List; @ConfigSerializable @@ -13,6 +15,12 @@ public class ProxyConfiguration { return this.debug; } + @Comment("") + private int randomAttempts = 5; + public int randomAttempts() { + return this.randomAttempts; + } + @Comment("List of login/registration servers") private List authServers = List.of("auth1", "auth2"); public List authServers() { @@ -41,6 +49,17 @@ public class ProxyConfiguration { public boolean ensureFirstServerIsAuthServer() { return this.ensureAuthServer; } + + @Comment(""" + SendMode + TO_FIRST | + TO_EMPTIEST_SERVE | + RANDOM | + """) + private SendMode sendMode = SendMode.RANDOM; + public SendMode sendMode() { + return this.sendMode; + } } @ConfigSerializable @@ -59,6 +78,18 @@ public class ProxyConfiguration { public List teleportServers() { return this.teleportServers; } + + // TODO: Improve comments + @Comment(""" + SendMode + TO_FIRST | + TO_EMPTIEST_SERVE | + RANDOM | + """) + private SendMode sendMode = SendMode.RANDOM; + public SendMode sendMode() { + return this.sendMode; + } } @ConfigSerializable @@ -80,4 +111,5 @@ public class ProxyConfiguration { } + } diff --git a/common/src/main/java/me/adrianed/authmevelocity/common/enums/SendMode.java b/common/src/main/java/me/adrianed/authmevelocity/common/enums/SendMode.java new file mode 100644 index 0000000..ee77c16 --- /dev/null +++ b/common/src/main/java/me/adrianed/authmevelocity/common/enums/SendMode.java @@ -0,0 +1,7 @@ +package me.adrianed.authmevelocity.common.enums; + +public enum SendMode { + TO_FIRST, + TO_EMPTIEST_SERVER, + RANDOM; +} diff --git a/velocity/src/main/java/me/adrianed/authmevelocity/velocity/listener/ConnectListener.java b/velocity/src/main/java/me/adrianed/authmevelocity/velocity/listener/ConnectListener.java index 4837bae..861b4ea 100644 --- a/velocity/src/main/java/me/adrianed/authmevelocity/velocity/listener/ConnectListener.java +++ b/velocity/src/main/java/me/adrianed/authmevelocity/velocity/listener/ConnectListener.java @@ -2,7 +2,6 @@ package me.adrianed.authmevelocity.velocity.listener; import java.util.Optional; -import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import com.google.common.io.ByteArrayDataOutput; @@ -18,6 +17,7 @@ import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.server.RegisteredServer; import me.adrianed.authmevelocity.velocity.AuthMeVelocityPlugin; +import me.adrianed.authmevelocity.velocity.utils.AuthmeUtils; public class ConnectListener { private final ProxyServer proxy; @@ -44,12 +44,14 @@ public class ConnectListener { plugin.logDebug("PlayerChooseInitialServerEvent | Player is in auth server"); return; } + var config = plugin.config().get(); + var server = AuthmeUtils.serverToSend( + config.ensureAuthServer().sendMode(), proxy, config.authServers(), config.randomAttempts()); - @Nullable RegisteredServer server = getAvailableServer(); // Velocity takes over in case the initial server is not present - event.setInitialServer(server); + event.setInitialServer(server.object()); continuation.resume(); - if (server == null) { + if (server.isEmpty()) { plugin.logDebug("PlayerChooseInitialServerEvent | Null server"); logger.error("Cannot send the player {} to an auth server", event.getPlayer().getUsername()); } @@ -82,13 +84,4 @@ public class ConnectListener { sv.sendPluginMessage(AuthMeVelocityPlugin.AUTHMEVELOCITY_CHANNEL, buf.toByteArray())); } } - - // TODO: Implement #40 - private @Nullable RegisteredServer getAvailableServer() { - for(String sv : plugin.config().get().authServers()){ - Optional opt = proxy.getServer(sv); - if (opt.isPresent()) return opt.get(); - } - return null; - } } diff --git a/velocity/src/main/java/me/adrianed/authmevelocity/velocity/listener/PluginMessageListener.java b/velocity/src/main/java/me/adrianed/authmevelocity/velocity/listener/PluginMessageListener.java index 8173f35..aa0f5d0 100644 --- a/velocity/src/main/java/me/adrianed/authmevelocity/velocity/listener/PluginMessageListener.java +++ b/velocity/src/main/java/me/adrianed/authmevelocity/velocity/listener/PluginMessageListener.java @@ -1,7 +1,5 @@ package me.adrianed.authmevelocity.velocity.listener; -import java.util.List; -import java.util.Random; import java.util.Locale; import me.adrianed.authmevelocity.api.velocity.event.PreSendOnLoginEvent; @@ -14,8 +12,6 @@ import me.adrianed.authmevelocity.common.MessageType; import com.google.common.io.ByteArrayDataInput; import com.velocitypowered.api.event.Continuation; import com.velocitypowered.api.event.Subscribe; -import com.velocitypowered.api.event.ResultedEvent.GenericResult; -import com.velocitypowered.api.proxy.ConnectionRequestBuilder.Result; import com.velocitypowered.api.event.connection.PluginMessageEvent; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.ProxyServer; @@ -23,6 +19,7 @@ import com.velocitypowered.api.proxy.ServerConnection; import com.velocitypowered.api.proxy.server.RegisteredServer; import me.adrianed.authmevelocity.velocity.AuthMeVelocityPlugin; +import me.adrianed.authmevelocity.velocity.utils.AuthmeUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -31,20 +28,18 @@ import org.slf4j.Logger; public class PluginMessageListener { private final ProxyServer proxy; private final Logger logger; - private final Random rm; private final AuthMeVelocityPlugin plugin; public PluginMessageListener(@NotNull ProxyServer proxy, @NotNull Logger logger, AuthMeVelocityPlugin plugin) { this.proxy = proxy; this.logger = logger; - this.rm = new Random(); this.plugin = plugin; } @Subscribe public void onPluginMessage(final PluginMessageEvent event, Continuation continuation) { final boolean cancelled = !event.getResult().isAllowed() - ||!(event.getSource() instanceof ServerConnection) + || !(event.getSource() instanceof ServerConnection) || !event.getIdentifier().equals(AuthMeVelocityPlugin.AUTHMEVELOCITY_CHANNEL); if (cancelled) { continuation.resume(); @@ -52,7 +47,7 @@ public class PluginMessageListener { return; } - final ServerConnection connection = ((ServerConnection)event.getSource()); + final ServerConnection connection = (ServerConnection) event.getSource(); event.setResult(PluginMessageEvent.ForwardResult.handled()); @@ -66,7 +61,7 @@ public class PluginMessageListener { switch (type) { case LOGIN -> { plugin.logDebug("PluginMessageEvent | Login type"); - if (player != null && plugin.addPlayer(player)){ + if (player != null && plugin.addPlayer(player)) { proxy.getEventManager().fireAndForget(new ProxyLoginEvent(player)); this.createServerConnectionRequest(player, connection); plugin.logDebug("PluginMessageEvent | Player not null"); @@ -88,7 +83,7 @@ public class PluginMessageListener { } case UNREGISTER -> { plugin.logDebug("PluginMessageEvent | Unregister type"); - if(player != null) { + if (player != null) { plugin.logDebug("PluginMessageEvent | Player not null"); proxy.getEventManager().fireAndForget(new ProxyUnregisterEvent(player)); } @@ -108,32 +103,35 @@ public class PluginMessageListener { } final RegisteredServer loginServer = player.getCurrentServer().orElse(connection).getServer(); - final String randomServer = this.getRandomServer(); - proxy.getServer(randomServer).ifPresentOrElse(server -> - proxy.getEventManager().fire(new PreSendOnLoginEvent(player, loginServer, server)) - .thenApply(PreSendOnLoginEvent::getResult) - .thenApply(GenericResult::isAllowed) - .thenAcceptAsync(allowed -> { - if (!allowed.booleanValue()) { + var config = plugin.config().get(); + + var toSend = AuthmeUtils.serverToSend( + config.sendOnLogin().sendMode(), proxy, config.authServers(), config.randomAttempts()); + + if (toSend.isEmpty()) { + if (toSend.string() != null) { + logger.warn("The server {} does not exist", toSend.string()); + } else { + logger.warn("There is not valid server to send"); + } + return; + } + + proxy.getEventManager().fire(new PreSendOnLoginEvent(player, loginServer, toSend.object())) + .thenAccept(event -> { + if (!event.getResult().isAllowed()) { return; } - player.createConnectionRequest(server) + player.createConnectionRequest(event.getResult().server()) .connect() - .thenApply(Result::isSuccessful) .thenAcceptAsync(result -> { - if(!result.booleanValue()) { + if (!result.isSuccessful()) { logger.info("Unable to connect the player {} to the server {}", player.getUsername(), - server.getServerInfo().getName()); + result.getAttemptedConnection().getServerInfo().getName()); } }); - }) - , () -> logger.warn("The server {} does not exist", randomServer)); - } - - private String getRandomServer() { - final List serverList = plugin.config().get().sendOnLogin().teleportServers(); - return serverList.get(rm.nextInt(serverList.size())); + }); } } diff --git a/velocity/src/main/java/me/adrianed/authmevelocity/velocity/utils/AuthmeUtils.java b/velocity/src/main/java/me/adrianed/authmevelocity/velocity/utils/AuthmeUtils.java index 3cdb52b..45a5dcf 100644 --- a/velocity/src/main/java/me/adrianed/authmevelocity/velocity/utils/AuthmeUtils.java +++ b/velocity/src/main/java/me/adrianed/authmevelocity/velocity/utils/AuthmeUtils.java @@ -1,9 +1,17 @@ package me.adrianed.authmevelocity.velocity.utils; +import java.util.List; import java.util.Objects; +import java.util.Optional; +import java.util.Random; import org.jetbrains.annotations.NotNull; +import com.velocitypowered.api.proxy.ProxyServer; +import com.velocitypowered.api.proxy.server.RegisteredServer; + +import me.adrianed.authmevelocity.common.enums.SendMode; + public class AuthmeUtils { //Origin: https://github.com/4drian3d/ChatRegulator/blob/main/src/main/java/me/dreamerzero/chatregulator/utils/CommandUtils.java#L71 /** @@ -18,5 +26,55 @@ public class AuthmeUtils { } return string.substring(0, index); } + + private static final Random RANDOM = new Random(); + + public static Pair serverToSend(SendMode sendMode, ProxyServer proxy, List servers, int attempts) { + return switch(sendMode) { + case TO_FIRST -> { + Optional sv; + for (final String st : servers) { + sv = proxy.getServer(st); + if (sv.isPresent()) yield Pair.of(st, sv.get()); + } + yield Pair.of(null, null); + } + case TO_EMPTIEST_SERVER -> { + RegisteredServer emptiest = null; + Optional optional = Optional.empty(); + for (final String st : servers) { + optional = proxy.getServer(st); + if (optional.isPresent()) { + RegisteredServer actualsv = optional.get(); + int actualConnected = actualsv.getPlayersConnected().size(); + if (actualConnected == 0) { + yield Pair.of(st, actualsv); + } + if (emptiest == null || actualConnected < emptiest.getPlayersConnected().size()) { + emptiest = actualsv; + } + } + } + yield Pair.of(optional.map(sv -> sv.getServerInfo().getName()).orElse(null), emptiest); + } + case RANDOM -> { + Optional server; + if (servers.size() == 1) { + server = proxy.getServer(servers.get(0)); + if (server.isPresent()) { + yield Pair.of(server.get().getServerInfo().getName(), server.get()); + } + } + for (int i = 0; i < attempts; i++) { + int value = RANDOM.nextInt(servers.size()); + server = proxy.getServer(servers.get(value)); + if (server.isPresent()) { + yield Pair.of(server.get().getServerInfo().getName(), server.get()); + } + } + yield Pair.of(null, null); + } + }; + } private AuthmeUtils() {} } diff --git a/velocity/src/main/java/me/adrianed/authmevelocity/velocity/utils/Pair.java b/velocity/src/main/java/me/adrianed/authmevelocity/velocity/utils/Pair.java new file mode 100644 index 0000000..8ae66c8 --- /dev/null +++ b/velocity/src/main/java/me/adrianed/authmevelocity/velocity/utils/Pair.java @@ -0,0 +1,15 @@ +package me.adrianed.authmevelocity.velocity.utils; + +public record Pair(String string, O object) { + public boolean isPresent() { + return this.object != null; + } + + public boolean isEmpty() { + return object == null; + } + + public static Pair of(String string, O object) { + return new Pair<>(string, object); + } +}