diff --git a/src/main/java/com/velocitypowered/proxy/VelocityServer.java b/src/main/java/com/velocitypowered/proxy/VelocityServer.java index 2019714e7..079f685d5 100644 --- a/src/main/java/com/velocitypowered/proxy/VelocityServer.java +++ b/src/main/java/com/velocitypowered/proxy/VelocityServer.java @@ -5,7 +5,10 @@ import com.google.gson.GsonBuilder; import com.velocitypowered.network.ConnectionManager; import com.velocitypowered.proxy.config.VelocityConfiguration; import com.velocitypowered.proxy.connection.http.NettyHttpClient; +import com.velocitypowered.proxy.data.ServerInfo; +import com.velocitypowered.proxy.util.AddressUtil; import com.velocitypowered.proxy.util.EncryptionUtils; +import com.velocitypowered.proxy.util.ServerMap; import io.netty.bootstrap.Bootstrap; import net.kyori.text.Component; import net.kyori.text.serializer.GsonComponentSerializer; @@ -18,6 +21,8 @@ import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.Paths; import java.security.KeyPair; +import java.util.HashMap; +import java.util.Map; public class VelocityServer { private static final Logger logger = LogManager.getLogger(VelocityServer.class); @@ -30,6 +35,7 @@ public class VelocityServer { private VelocityConfiguration configuration; private NettyHttpClient httpClient; private KeyPair serverKeyPair; + private final ServerMap servers = new ServerMap(); private VelocityServer() { } @@ -67,6 +73,11 @@ public class VelocityServer { logger.error("Unable to load your velocity.toml. The server will shut down.", e); System.exit(1); } + + for (Map.Entry entry : configuration.getServers().entrySet()) { + servers.register(new ServerInfo(entry.getKey(), AddressUtil.parseAddress(entry.getValue()))); + } + serverKeyPair = EncryptionUtils.createRsaKeyPair(1024); httpClient = new NettyHttpClient(this); @@ -74,6 +85,10 @@ public class VelocityServer { this.cm.bind(configuration.getBind()); } + public ServerMap getServers() { + return servers; + } + public Bootstrap initializeGenericBootstrap() { return this.cm.createWorker(); } diff --git a/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java b/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java index f474a4383..4d2e8a1bc 100644 --- a/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java +++ b/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java @@ -1,5 +1,7 @@ package com.velocitypowered.proxy.connection.client; +import com.google.common.base.Preconditions; +import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation; import com.velocitypowered.proxy.data.GameProfile; import com.velocitypowered.proxy.protocol.packets.Chat; @@ -19,6 +21,8 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.net.InetSocketAddress; +import java.util.List; +import java.util.Optional; import java.util.UUID; public class ConnectedPlayer implements MinecraftConnectionAssociation { @@ -28,6 +32,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation { private final GameProfile profile; private final MinecraftConnection connection; + private int tryIndex = 0; private ServerConnection connectedServer; private ClientSettings clientSettings; @@ -106,7 +111,27 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation { } } + public Optional getNextServerToTry() { + List serversToTry = VelocityServer.getServer().getConfiguration().getAttemptConnectionOrder(); + if (tryIndex >= serversToTry.size()) { + return Optional.empty(); + } + + String toTryName = serversToTry.get(tryIndex); + tryIndex++; + return VelocityServer.getServer().getServers().getServer(toTryName); + } + + public void connect(ServerInfo info) { + Preconditions.checkNotNull(info, "info"); + ServerConnection connection = new ServerConnection(info, this, VelocityServer.getServer()); + connection.connect(); + } + public void setConnectedServer(ServerConnection serverConnection) { + if (this.connectedServer != null && !serverConnection.getServerInfo().equals(connectedServer.getServerInfo())) { + this.tryIndex = 0; + } this.connectedServer = serverConnection; } diff --git a/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java b/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java index 52b06e4be..c3ebac385 100644 --- a/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java +++ b/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java @@ -12,6 +12,8 @@ import com.velocitypowered.proxy.connection.backend.ServerConnection; import com.velocitypowered.proxy.data.ServerInfo; import com.velocitypowered.proxy.util.EncryptionUtils; import com.velocitypowered.proxy.util.UuidUtils; +import net.kyori.text.TextComponent; +import net.kyori.text.format.TextColor; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -20,6 +22,7 @@ import java.net.URL; import java.security.GeneralSecurityException; import java.security.KeyPair; import java.util.Arrays; +import java.util.Optional; import java.util.concurrent.ThreadLocalRandom; public class LoginSessionHandler implements MinecraftSessionHandler { @@ -95,6 +98,14 @@ public class LoginSessionHandler implements MinecraftSessionHandler { } private void handleSuccessfulLogin(GameProfile profile) { + // Initiate a regular connection and move over to it. + ConnectedPlayer player = new ConnectedPlayer(profile, inbound); + Optional toTry = player.getNextServerToTry(); + if (!toTry.isPresent()) { + player.close(TextComponent.of("No available servers", TextColor.RED)); + return; + } + inbound.write(new SetCompression(256)); inbound.setCompressionThreshold(256); @@ -103,15 +114,10 @@ public class LoginSessionHandler implements MinecraftSessionHandler { success.setUuid(profile.idAsUuid()); inbound.write(success); - // Initiate a regular connection and move over to it. - ConnectedPlayer player = new ConnectedPlayer(profile, inbound); logger.info("{} has connected", player); inbound.setAssociation(player); - ServerInfo info = new ServerInfo("test", new InetSocketAddress("localhost", 25565)); - ServerConnection connection = new ServerConnection(info, player, VelocityServer.getServer()); - inbound.setState(StateRegistry.PLAY); inbound.setSessionHandler(new InitialConnectSessionHandler(player)); - connection.connect(); + player.connect(toTry.get()); } } diff --git a/src/main/java/com/velocitypowered/proxy/data/ServerInfo.java b/src/main/java/com/velocitypowered/proxy/data/ServerInfo.java index 36ed6658c..833e404c0 100644 --- a/src/main/java/com/velocitypowered/proxy/data/ServerInfo.java +++ b/src/main/java/com/velocitypowered/proxy/data/ServerInfo.java @@ -1,22 +1,24 @@ package com.velocitypowered.proxy.data; +import com.google.common.base.Preconditions; + import java.net.InetSocketAddress; import java.util.Objects; -public class ServerInfo { +public final class ServerInfo { private final String name; private final InetSocketAddress address; public ServerInfo(String name, InetSocketAddress address) { - this.name = name; - this.address = address; + this.name = Preconditions.checkNotNull(name, "name"); + this.address = Preconditions.checkNotNull(address, "address"); } - public String getName() { + public final String getName() { return name; } - public InetSocketAddress getAddress() { + public final InetSocketAddress getAddress() { return address; } @@ -29,7 +31,7 @@ public class ServerInfo { } @Override - public boolean equals(Object o) { + public final boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ServerInfo that = (ServerInfo) o; @@ -38,7 +40,7 @@ public class ServerInfo { } @Override - public int hashCode() { + public final int hashCode() { return Objects.hash(name, address); } } diff --git a/src/main/java/com/velocitypowered/proxy/util/ServerMap.java b/src/main/java/com/velocitypowered/proxy/util/ServerMap.java new file mode 100644 index 000000000..bea4b4b21 --- /dev/null +++ b/src/main/java/com/velocitypowered/proxy/util/ServerMap.java @@ -0,0 +1,28 @@ +package com.velocitypowered.proxy.util; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.velocitypowered.proxy.data.ServerInfo; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public class ServerMap { + private final Map servers = new HashMap<>(); + + public Optional getServer(String name) { + Preconditions.checkNotNull(name, "name"); + return Optional.ofNullable(servers.get(name.toLowerCase())); + } + + public Collection getAllServers() { + return ImmutableList.copyOf(servers.values()); + } + + public void register(ServerInfo info) { + Preconditions.checkNotNull(info, "info"); + servers.put(info.getName(), info); + } +}