diff --git a/api/src/main/java/com/velocitypowered/api/proxy/ProxyServer.java b/api/src/main/java/com/velocitypowered/api/proxy/ProxyServer.java new file mode 100644 index 000000000..7ff2d8ea9 --- /dev/null +++ b/api/src/main/java/com/velocitypowered/api/proxy/ProxyServer.java @@ -0,0 +1,32 @@ +package com.velocitypowered.api.proxy; + +import javax.annotation.Nonnull; +import java.util.Collection; +import java.util.Optional; +import java.util.UUID; + +/** + * Represents a Minecraft proxy server that follows the Velocity API. + */ +public interface ProxyServer { + /** + * Retrieves the player currently connected to this proxy by their Minecraft username. + * @param username the username + * @return an {@link Optional} with the player + */ + Optional getPlayer(@Nonnull String username); + + /** + * Retrieves the player currently connected to this proxy by their Minecraft UUID. + * @param uuid the UUID + * @return an {@link Optional} with the player + */ + Optional getPlayer(@Nonnull UUID uuid); + + /** + * Retrieves all players currently connected to this proxy. This call may or may not be a snapshot of all players + * online. + * @return the players online on this proxy + */ + Collection getAllPlayers(); +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java index cedf2910e..174ff6012 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java @@ -1,10 +1,16 @@ package com.velocitypowered.proxy; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.natives.util.Natives; import com.velocitypowered.network.ConnectionManager; import com.velocitypowered.proxy.config.VelocityConfiguration; +import com.velocitypowered.proxy.connection.MinecraftConnection; +import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.connection.http.NettyHttpClient; import com.velocitypowered.api.server.ServerInfo; import com.velocitypowered.proxy.util.AddressUtil; @@ -16,15 +22,20 @@ import net.kyori.text.serializer.GsonComponentSerializer; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import javax.annotation.Nonnull; import java.io.IOException; import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.Paths; import java.security.KeyPair; +import java.util.Collection; import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; -public class VelocityServer { +public class VelocityServer implements ProxyServer { private static final Logger logger = LogManager.getLogger(VelocityServer.class); private static final VelocityServer INSTANCE = new VelocityServer(); public static final Gson GSON = new GsonBuilder() @@ -37,6 +48,9 @@ public class VelocityServer { private KeyPair serverKeyPair; private final ServerMap servers = new ServerMap(); + private final Map connectionsByUuid = new ConcurrentHashMap<>(); + private final Map connectionsByName = new ConcurrentHashMap<>(); + private VelocityServer() { } @@ -103,4 +117,31 @@ public class VelocityServer { public NettyHttpClient getHttpClient() { return httpClient; } + + public void registerConnection(ConnectedPlayer connection) { + connectionsByName.put(connection.getUsername(), connection); + connectionsByUuid.put(connection.getUniqueId(), connection); + } + + public void unregisterConnection(ConnectedPlayer connection) { + connectionsByName.remove(connection.getUsername(), connection); + connectionsByUuid.remove(connection.getUniqueId(), connection); + } + + @Override + public Optional getPlayer(@Nonnull String username) { + Preconditions.checkNotNull(username, "username"); + return Optional.ofNullable(connectionsByName.get(username)); + } + + @Override + public Optional getPlayer(@Nonnull UUID uuid) { + Preconditions.checkNotNull(uuid, "uuid"); + return Optional.ofNullable(connectionsByUuid.get(uuid)); + } + + @Override + public Collection getAllPlayers() { + return ImmutableList.copyOf(connectionsByUuid.values()); + } } 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 55f89951a..dda03be7e 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 @@ -209,6 +209,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { if (connectedServer != null) { connectedServer.disconnect(); } + VelocityServer.getServer().unregisterConnection(this); } @Override 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 12e69a4eb..1826baa48 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 @@ -140,6 +140,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler { inbound.setAssociation(player); inbound.setState(StateRegistry.PLAY); inbound.setSessionHandler(new InitialConnectSessionHandler(player)); + VelocityServer.getServer().registerConnection(player); player.createConnectionRequest(toTry.get()).fireAndForget(); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressEncoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressEncoder.java index f62834b93..802f45121 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressEncoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressEncoder.java @@ -28,6 +28,15 @@ public class MinecraftCompressEncoder extends MessageToByteEncoder { } } + @Override + protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, ByteBuf msg, boolean preferDirect) throws Exception { + if (msg.readableBytes() <= threshold) { + return ctx.alloc().directBuffer(msg.readableBytes() + 1); + } + // A reasonable assumption about compression savings + return ctx.alloc().directBuffer(msg.readableBytes() / 3); + } + @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { compressor.dispose();