3
0
Mirror von https://github.com/PaperMC/Velocity.git synchronisiert 2024-11-17 05:20:14 +01:00

Introduce RegisteredServer API

This interface roughly maps the BungeeCord ServerInfo API. Accordingly,
this is a breaking API change, as many of the server-related events and
methods working with server info instances now provide/expect the
RegisteredServer interface instead.
Dieser Commit ist enthalten in:
Andrew Steinborn 2018-09-16 02:26:29 -04:00
Ursprung 88b7407aaf
Commit e1b2dc0d43
19 geänderte Dateien mit 331 neuen und 159 gelöschten Zeilen

Datei anzeigen

@ -3,6 +3,7 @@ package com.velocitypowered.api.event.player;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.velocitypowered.api.event.ResultedEvent; import com.velocitypowered.api.event.ResultedEvent;
import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.api.proxy.server.ServerInfo;
import net.kyori.text.Component; import net.kyori.text.Component;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
@ -13,12 +14,12 @@ import org.checkerframework.checker.nullness.qual.NonNull;
*/ */
public class KickedFromServerEvent implements ResultedEvent<KickedFromServerEvent.ServerKickResult> { public class KickedFromServerEvent implements ResultedEvent<KickedFromServerEvent.ServerKickResult> {
private final Player player; private final Player player;
private final ServerInfo server; private final RegisteredServer server;
private final Component originalReason; private final Component originalReason;
private final boolean duringLogin; private final boolean duringLogin;
private ServerKickResult result; private ServerKickResult result;
public KickedFromServerEvent(Player player, ServerInfo server, Component originalReason, boolean duringLogin, Component fancyReason) { public KickedFromServerEvent(Player player, RegisteredServer server, Component originalReason, boolean duringLogin, Component fancyReason) {
this.player = Preconditions.checkNotNull(player, "player"); this.player = Preconditions.checkNotNull(player, "player");
this.server = Preconditions.checkNotNull(server, "server"); this.server = Preconditions.checkNotNull(server, "server");
this.originalReason = Preconditions.checkNotNull(originalReason, "originalReason"); this.originalReason = Preconditions.checkNotNull(originalReason, "originalReason");
@ -40,7 +41,7 @@ public class KickedFromServerEvent implements ResultedEvent<KickedFromServerEven
return player; return player;
} }
public ServerInfo getServer() { public RegisteredServer getServer() {
return server; return server;
} }
@ -91,9 +92,9 @@ public class KickedFromServerEvent implements ResultedEvent<KickedFromServerEven
* when this result is used. * when this result is used.
*/ */
public static class RedirectPlayer implements ServerKickResult { public static class RedirectPlayer implements ServerKickResult {
private final ServerInfo server; private final RegisteredServer server;
private RedirectPlayer(ServerInfo server) { private RedirectPlayer(RegisteredServer server) {
this.server = Preconditions.checkNotNull(server, "server"); this.server = Preconditions.checkNotNull(server, "server");
} }
@ -102,7 +103,7 @@ public class KickedFromServerEvent implements ResultedEvent<KickedFromServerEven
return false; return false;
} }
public ServerInfo getServer() { public RegisteredServer getServer() {
return server; return server;
} }
@ -111,7 +112,7 @@ public class KickedFromServerEvent implements ResultedEvent<KickedFromServerEven
* @param server the server to send the player to * @param server the server to send the player to
* @return the redirect result * @return the redirect result
*/ */
public static RedirectPlayer create(ServerInfo server) { public static RedirectPlayer create(RegisteredServer server) {
return new RedirectPlayer(server); return new RedirectPlayer(server);
} }
} }

Datei anzeigen

@ -2,7 +2,7 @@ package com.velocitypowered.api.event.player;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.api.proxy.server.RegisteredServer;
/** /**
* This event is fired once the player has successfully connected to the target server and the connection to the previous * This event is fired once the player has successfully connected to the target server and the connection to the previous
@ -10,9 +10,9 @@ import com.velocitypowered.api.proxy.server.ServerInfo;
*/ */
public class ServerConnectedEvent { public class ServerConnectedEvent {
private final Player player; private final Player player;
private final ServerInfo server; private final RegisteredServer server;
public ServerConnectedEvent(Player player, ServerInfo server) { public ServerConnectedEvent(Player player, RegisteredServer server) {
this.player = Preconditions.checkNotNull(player, "player"); this.player = Preconditions.checkNotNull(player, "player");
this.server = Preconditions.checkNotNull(server, "server"); this.server = Preconditions.checkNotNull(server, "server");
} }
@ -21,7 +21,7 @@ public class ServerConnectedEvent {
return player; return player;
} }
public ServerInfo getServer() { public RegisteredServer getServer() {
return server; return server;
} }

Datei anzeigen

@ -3,6 +3,7 @@ package com.velocitypowered.api.event.player;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.velocitypowered.api.event.ResultedEvent; import com.velocitypowered.api.event.ResultedEvent;
import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.api.proxy.server.ServerInfo;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
@ -14,10 +15,10 @@ import java.util.Optional;
*/ */
public class ServerPreConnectEvent implements ResultedEvent<ServerPreConnectEvent.ServerResult> { public class ServerPreConnectEvent implements ResultedEvent<ServerPreConnectEvent.ServerResult> {
private final Player player; private final Player player;
private final ServerInfo originalServer; private final RegisteredServer originalServer;
private ServerResult result; private ServerResult result;
public ServerPreConnectEvent(Player player, ServerInfo originalServer) { public ServerPreConnectEvent(Player player, RegisteredServer originalServer) {
this.player = Preconditions.checkNotNull(player, "player"); this.player = Preconditions.checkNotNull(player, "player");
this.originalServer = Preconditions.checkNotNull(originalServer, "originalServer"); this.originalServer = Preconditions.checkNotNull(originalServer, "originalServer");
this.result = ServerResult.allowed(originalServer); this.result = ServerResult.allowed(originalServer);
@ -37,7 +38,7 @@ public class ServerPreConnectEvent implements ResultedEvent<ServerPreConnectEven
this.result = Preconditions.checkNotNull(result, "result"); this.result = Preconditions.checkNotNull(result, "result");
} }
public ServerInfo getOriginalServer() { public RegisteredServer getOriginalServer() {
return originalServer; return originalServer;
} }
@ -57,9 +58,9 @@ public class ServerPreConnectEvent implements ResultedEvent<ServerPreConnectEven
private static final ServerResult DENIED = new ServerResult(false, null); private static final ServerResult DENIED = new ServerResult(false, null);
private final boolean allowed; private final boolean allowed;
private final ServerInfo server; private final RegisteredServer server;
private ServerResult(boolean allowed, @Nullable ServerInfo server) { private ServerResult(boolean allowed, @Nullable RegisteredServer server) {
this.allowed = allowed; this.allowed = allowed;
this.server = server; this.server = server;
} }
@ -69,7 +70,7 @@ public class ServerPreConnectEvent implements ResultedEvent<ServerPreConnectEven
return allowed; return allowed;
} }
public Optional<ServerInfo> getServer() { public Optional<RegisteredServer> getServer() {
return Optional.ofNullable(server); return Optional.ofNullable(server);
} }
@ -78,14 +79,14 @@ public class ServerPreConnectEvent implements ResultedEvent<ServerPreConnectEven
if (!allowed) { if (!allowed) {
return "denied"; return "denied";
} }
return "allowed: connect to " + server.getName(); return "allowed: connect to " + server.getServerInfo().getName();
} }
public static ServerResult denied() { public static ServerResult denied() {
return DENIED; return DENIED;
} }
public static ServerResult allowed(ServerInfo server) { public static ServerResult allowed(RegisteredServer server) {
Preconditions.checkNotNull(server, "server"); Preconditions.checkNotNull(server, "server");
return new ServerResult(true, server); return new ServerResult(true, server);
} }

Datei anzeigen

@ -1,5 +1,6 @@
package com.velocitypowered.api.proxy; package com.velocitypowered.api.proxy;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.api.proxy.server.ServerInfo;
import net.kyori.text.Component; import net.kyori.text.Component;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
@ -9,21 +10,21 @@ import java.util.concurrent.CompletableFuture;
/** /**
* Provides a fluent interface to compose and send a connection request to another server behind the proxy. A connection * Provides a fluent interface to compose and send a connection request to another server behind the proxy. A connection
* request is created using {@link Player#createConnectionRequest(ServerInfo)}. * request is created using {@link Player#createConnectionRequest(RegisteredServer)}.
*/ */
public interface ConnectionRequestBuilder { public interface ConnectionRequestBuilder {
/** /**
* Returns the server that this connection request represents. * Returns the server that this connection request represents.
* @return the server this request will connect to * @return the server this request will connect to
*/ */
@NonNull ServerInfo getServer(); RegisteredServer getServer();
/** /**
* Initiates the connection to the remote server and emits a result on the {@link CompletableFuture} after the user * Initiates the connection to the remote server and emits a result on the {@link CompletableFuture} after the user
* has logged on. No messages will be communicated to the client: the user is responsible for all error handling. * has logged on. No messages will be communicated to the client: the user is responsible for all error handling.
* @return a {@link CompletableFuture} representing the status of this connection * @return a {@link CompletableFuture} representing the status of this connection
*/ */
@NonNull CompletableFuture<Result> connect(); CompletableFuture<Result> connect();
/** /**
* Initiates the connection to the remote server without waiting for a result. Velocity will use generic error * Initiates the connection to the remote server without waiting for a result. Velocity will use generic error

Datei anzeigen

@ -4,6 +4,7 @@ import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.player.PlayerSettings; import com.velocitypowered.api.proxy.player.PlayerSettings;
import com.velocitypowered.api.proxy.messages.ChannelMessageSink; import com.velocitypowered.api.proxy.messages.ChannelMessageSink;
import com.velocitypowered.api.proxy.messages.ChannelMessageSource; import com.velocitypowered.api.proxy.messages.ChannelMessageSource;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.api.proxy.server.ServerInfo;
import com.velocitypowered.api.util.MessagePosition; import com.velocitypowered.api.util.MessagePosition;
import net.kyori.text.Component; import net.kyori.text.Component;
@ -59,10 +60,10 @@ public interface Player extends CommandSource, InboundConnection, ChannelMessage
/** /**
* Creates a new connection request so that the player can connect to another server. * Creates a new connection request so that the player can connect to another server.
* @param info the server to connect to * @param server the server to connect to
* @return a new connection request * @return a new connection request
*/ */
ConnectionRequestBuilder createConnectionRequest(@NonNull ServerInfo info); ConnectionRequestBuilder createConnectionRequest(@NonNull RegisteredServer server);
/** /**
* Sets the tab list header and footer for the player. * Sets the tab list header and footer for the player.

Datei anzeigen

@ -5,6 +5,7 @@ import com.velocitypowered.api.command.CommandManager;
import com.velocitypowered.api.event.EventManager; import com.velocitypowered.api.event.EventManager;
import com.velocitypowered.api.plugin.PluginManager; import com.velocitypowered.api.plugin.PluginManager;
import com.velocitypowered.api.proxy.messages.ChannelRegistrar; import com.velocitypowered.api.proxy.messages.ChannelRegistrar;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.scheduler.Scheduler; import com.velocitypowered.api.scheduler.Scheduler;
import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.api.proxy.server.ServerInfo;
@ -45,23 +46,24 @@ public interface ProxyServer {
int getPlayerCount(); int getPlayerCount();
/** /**
* Retrieves a registered {@link ServerInfo} instance by its name. The search is case-insensitive. * Retrieves a registered {@link RegisteredServer} instance by its name. The search is case-insensitive.
* @param name the name of the server * @param name the name of the server
* @return the registered server, which may be empty * @return the registered server, which may be empty
*/ */
Optional<ServerInfo> getServerInfo(String name); Optional<RegisteredServer> getServerInfo(String name);
/** /**
* Retrieves all {@link ServerInfo}s registered with this proxy. * Retrieves all {@link RegisteredServer}s registered with this proxy.
* @return the servers registered with this proxy * @return the servers registered with this proxy
*/ */
Collection<ServerInfo> getAllServers(); Collection<RegisteredServer> getAllServers();
/** /**
* Registers a server with this proxy. A server with this name should not already exist. * Registers a server with this proxy. A server with this name should not already exist.
* @param server the server to register * @param server the server to register
* @return the newly registered server
*/ */
void registerServer(ServerInfo server); RegisteredServer registerServer(ServerInfo server);
/** /**
* Unregisters this server from the proxy. * Unregisters this server from the proxy.

Datei anzeigen

@ -2,6 +2,7 @@ package com.velocitypowered.api.proxy;
import com.velocitypowered.api.proxy.messages.ChannelMessageSink; import com.velocitypowered.api.proxy.messages.ChannelMessageSink;
import com.velocitypowered.api.proxy.messages.ChannelMessageSource; import com.velocitypowered.api.proxy.messages.ChannelMessageSource;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.api.proxy.server.ServerInfo;
/** /**
@ -12,6 +13,12 @@ public interface ServerConnection extends ChannelMessageSource, ChannelMessageSi
* Returns the server that this connection is connected to. * Returns the server that this connection is connected to.
* @return the server this connection is connected to * @return the server this connection is connected to
*/ */
RegisteredServer getServer();
/**
* Returns the server info for this connection.
* @return the server info for this connection
*/
ServerInfo getServerInfo(); ServerInfo getServerInfo();
/** /**

Datei anzeigen

@ -8,6 +8,7 @@ public interface ChannelMessageSink {
* Sends a plugin message to this target. * Sends a plugin message to this target.
* @param identifier the channel identifier to send the message on * @param identifier the channel identifier to send the message on
* @param data the data to send * @param data the data to send
* @return whether or not the message could be sent
*/ */
void sendPluginMessage(ChannelIdentifier identifier, byte[] data); boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data);
} }

Datei anzeigen

@ -0,0 +1,30 @@
package com.velocitypowered.api.proxy.server;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.messages.ChannelMessageSink;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
/**
* Represents a server that has been registered with the proxy.
*/
public interface RegisteredServer extends ChannelMessageSink {
/**
* Returns the {@link ServerInfo} for this server.
* @return the server info
*/
ServerInfo getServerInfo();
/**
* Returns a list of all the players currently connected to this server on this proxy.
* @return the players on this proxy
*/
Collection<Player> getPlayersConnected();
/**
* Attempts to ping the remote server and return the server list ping result.
* @return the server ping result from the server
*/
CompletableFuture<ServerPing> ping();
}

Datei anzeigen

@ -10,6 +10,7 @@ import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent; import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.util.Favicon; import com.velocitypowered.api.util.Favicon;
import com.velocitypowered.api.plugin.PluginManager; import com.velocitypowered.api.plugin.PluginManager;
import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.api.proxy.server.ServerInfo;
@ -30,7 +31,7 @@ import com.velocitypowered.proxy.scheduler.VelocityScheduler;
import com.velocitypowered.proxy.util.AddressUtil; import com.velocitypowered.proxy.util.AddressUtil;
import com.velocitypowered.proxy.util.EncryptionUtils; import com.velocitypowered.proxy.util.EncryptionUtils;
import com.velocitypowered.proxy.util.Ratelimiter; import com.velocitypowered.proxy.util.Ratelimiter;
import com.velocitypowered.proxy.util.ServerMap; import com.velocitypowered.proxy.server.ServerMap;
import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.Bootstrap;
import net.kyori.text.Component; import net.kyori.text.Component;
import net.kyori.text.TextComponent; import net.kyori.text.TextComponent;
@ -61,7 +62,7 @@ public class VelocityServer implements ProxyServer {
private VelocityConfiguration configuration; private VelocityConfiguration configuration;
private NettyHttpClient httpClient; private NettyHttpClient httpClient;
private KeyPair serverKeyPair; private KeyPair serverKeyPair;
private final ServerMap servers = new ServerMap(); private final ServerMap servers = new ServerMap(this);
private final VelocityCommandManager commandManager = new VelocityCommandManager(); private final VelocityCommandManager commandManager = new VelocityCommandManager();
private final AtomicBoolean shutdownInProgress = new AtomicBoolean(false); private final AtomicBoolean shutdownInProgress = new AtomicBoolean(false);
private boolean shutdown = false; private boolean shutdown = false;
@ -263,19 +264,19 @@ public class VelocityServer implements ProxyServer {
} }
@Override @Override
public Optional<ServerInfo> getServerInfo(String name) { public Optional<RegisteredServer> getServerInfo(String name) {
Preconditions.checkNotNull(name, "name"); Preconditions.checkNotNull(name, "name");
return servers.getServer(name); return servers.getServer(name);
} }
@Override @Override
public Collection<ServerInfo> getAllServers() { public Collection<RegisteredServer> getAllServers() {
return servers.getAllServers(); return servers.getAllServers();
} }
@Override @Override
public void registerServer(ServerInfo server) { public RegisteredServer registerServer(ServerInfo server) {
servers.register(server); return servers.register(server);
} }
@Override @Override

Datei anzeigen

@ -6,6 +6,7 @@ import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.ServerConnection; import com.velocitypowered.api.proxy.ServerConnection;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.api.proxy.server.ServerInfo;
import net.kyori.text.TextComponent; import net.kyori.text.TextComponent;
import net.kyori.text.event.ClickEvent; import net.kyori.text.event.ClickEvent;
@ -34,7 +35,7 @@ public class ServerCommand implements Command {
if (args.length == 1) { if (args.length == 1) {
// Trying to connect to a server. // Trying to connect to a server.
String serverName = args[0]; String serverName = args[0];
Optional<ServerInfo> toConnect = server.getServerInfo(serverName); Optional<RegisteredServer> toConnect = server.getServerInfo(serverName);
if (!toConnect.isPresent()) { if (!toConnect.isPresent()) {
player.sendMessage(TextComponent.of("Server " + serverName + " doesn't exist.", TextColor.RED)); player.sendMessage(TextComponent.of("Server " + serverName + " doesn't exist.", TextColor.RED));
return; return;
@ -48,17 +49,19 @@ public class ServerCommand implements Command {
// Assemble the list of servers as components // Assemble the list of servers as components
TextComponent.Builder serverListBuilder = TextComponent.builder("Available servers: ").color(TextColor.YELLOW); TextComponent.Builder serverListBuilder = TextComponent.builder("Available servers: ").color(TextColor.YELLOW);
List<ServerInfo> infos = ImmutableList.copyOf(server.getAllServers()); List<RegisteredServer> infos = ImmutableList.copyOf(server.getAllServers());
for (int i = 0; i < infos.size(); i++) { for (int i = 0; i < infos.size(); i++) {
ServerInfo serverInfo = infos.get(i); RegisteredServer rs = infos.get(i);
TextComponent infoComponent = TextComponent.of(serverInfo.getName()); TextComponent infoComponent = TextComponent.of(rs.getServerInfo().getName());
if (serverInfo.getName().equals(currentServer)) { String playersText = rs.getPlayersConnected().size() + " player(s) online";
if (rs.getServerInfo().getName().equals(currentServer)) {
infoComponent = infoComponent.color(TextColor.GREEN) infoComponent = infoComponent.color(TextColor.GREEN)
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Currently connected to this server"))); .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT,
TextComponent.of("Currently connected to this server\n" + playersText)));
} else { } else {
infoComponent = infoComponent.color(TextColor.GRAY) infoComponent = infoComponent.color(TextColor.GRAY)
.clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/server " + serverInfo.getName())) .clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/server " + rs.getServerInfo().getName()))
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to connect to this server"))); .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to connect to this server\n" + playersText)));
} }
serverListBuilder.append(infoComponent); serverListBuilder.append(infoComponent);
if (i != infos.size() - 1) { if (i != infos.size() - 1) {
@ -74,11 +77,11 @@ public class ServerCommand implements Command {
public List<String> suggest(CommandSource source, String[] currentArgs) { public List<String> suggest(CommandSource source, String[] currentArgs) {
if (currentArgs.length == 0) { if (currentArgs.length == 0) {
return server.getAllServers().stream() return server.getAllServers().stream()
.map(ServerInfo::getName) .map(rs -> rs.getServerInfo().getName())
.collect(Collectors.toList()); .collect(Collectors.toList());
} else if (currentArgs.length == 1) { } else if (currentArgs.length == 1) {
return server.getAllServers().stream() return server.getAllServers().stream()
.map(ServerInfo::getName) .map(rs -> rs.getServerInfo().getName())
.filter(name -> name.regionMatches(true, 0, currentArgs[0], 0, currentArgs[0].length())) .filter(name -> name.regionMatches(true, 0, currentArgs[0], 0, currentArgs[0].length()))
.collect(Collectors.toList()); .collect(Collectors.toList());
} else { } else {

Datei anzeigen

@ -25,7 +25,8 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
@Override @Override
public void activated() { public void activated() {
server.getEventManager().fireAndForget(new ServerConnectedEvent(connection.getPlayer(), connection.getServerInfo())); server.getEventManager().fireAndForget(new ServerConnectedEvent(connection.getPlayer(), connection.getServer()));
connection.getServer().addPlayer(connection.getPlayer());
} }
@Override @Override
@ -46,7 +47,7 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
} else if (packet instanceof Disconnect) { } else if (packet instanceof Disconnect) {
Disconnect original = (Disconnect) packet; Disconnect original = (Disconnect) packet;
connection.disconnect(); connection.disconnect();
connection.getPlayer().handleConnectionException(connection.getServerInfo(), original); connection.getPlayer().handleConnectionException(connection.getServer(), original);
} else if (packet instanceof JoinGame) { } else if (packet instanceof JoinGame) {
playerHandler.handleBackendJoinGame((JoinGame) packet); playerHandler.handleBackendJoinGame((JoinGame) packet);
} else if (packet instanceof BossBar) { } else if (packet instanceof BossBar) {
@ -112,7 +113,7 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
@Override @Override
public void exception(Throwable throwable) { public void exception(Throwable throwable) {
connection.getPlayer().handleConnectionException(connection.getServerInfo(), throwable); connection.getPlayer().handleConnectionException(connection.getServer(), throwable);
} }
public VelocityServer getServer() { public VelocityServer getServer() {
@ -121,10 +122,11 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
@Override @Override
public void disconnected() { public void disconnected() {
if (connection.isGracefulDisconnect()) { connection.getServer().removePlayer(connection.getPlayer());
return; if (!connection.isGracefulDisconnect()) {
connection.getPlayer().handleConnectionException(connection.getServer(), Disconnect.create(
ConnectionMessages.UNEXPECTED_DISCONNECT));
} }
connection.getPlayer().handleConnectionException(connection.getServerInfo(), Disconnect.create(ConnectionMessages.UNEXPECTED_DISCONNECT));
} }
private boolean canForwardPluginMessage(PluginMessage message) { private boolean canForwardPluginMessage(PluginMessage message) {

Datei anzeigen

@ -4,6 +4,7 @@ import com.google.common.base.Preconditions;
import com.velocitypowered.api.proxy.ConnectionRequestBuilder; import com.velocitypowered.api.proxy.ConnectionRequestBuilder;
import com.velocitypowered.api.proxy.ServerConnection; import com.velocitypowered.api.proxy.ServerConnection;
import com.velocitypowered.api.proxy.messages.ChannelIdentifier; import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.proxy.config.PlayerInfoForwarding; import com.velocitypowered.proxy.config.PlayerInfoForwarding;
import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation; import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation;
import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.ProtocolConstants;
@ -19,6 +20,7 @@ import com.velocitypowered.proxy.protocol.StateRegistry;
import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.api.proxy.server.ServerInfo;
import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.server.VelocityRegisteredServer;
import io.netty.channel.*; import io.netty.channel.*;
import io.netty.handler.timeout.ReadTimeoutHandler; import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.util.AttributeKey; import io.netty.util.AttributeKey;
@ -38,7 +40,7 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
static final AttributeKey<CompletableFuture<ConnectionRequestBuilder.Result>> CONNECTION_NOTIFIER = static final AttributeKey<CompletableFuture<ConnectionRequestBuilder.Result>> CONNECTION_NOTIFIER =
AttributeKey.newInstance("connection-notification-result"); AttributeKey.newInstance("connection-notification-result");
private final ServerInfo serverInfo; private final VelocityRegisteredServer registeredServer;
private final ConnectedPlayer proxyPlayer; private final ConnectedPlayer proxyPlayer;
private final VelocityServer server; private final VelocityServer server;
private MinecraftConnection minecraftConnection; private MinecraftConnection minecraftConnection;
@ -46,8 +48,8 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
private boolean hasCompletedJoin = false; private boolean hasCompletedJoin = false;
private boolean gracefulDisconnect = false; private boolean gracefulDisconnect = false;
public VelocityServerConnection(ServerInfo target, ConnectedPlayer proxyPlayer, VelocityServer server) { public VelocityServerConnection(VelocityRegisteredServer registeredServer, ConnectedPlayer proxyPlayer, VelocityServer server) {
this.serverInfo = target; this.registeredServer = registeredServer;
this.proxyPlayer = proxyPlayer; this.proxyPlayer = proxyPlayer;
this.server = server; this.server = server;
} }
@ -72,7 +74,7 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
ch.pipeline().addLast(HANDLER, connection); ch.pipeline().addLast(HANDLER, connection);
} }
}) })
.connect(serverInfo.getAddress()) .connect(registeredServer.getServerInfo().getAddress())
.addListener(new ChannelFutureListener() { .addListener(new ChannelFutureListener() {
@Override @Override
public void operationComplete(ChannelFuture future) throws Exception { public void operationComplete(ChannelFuture future) throws Exception {
@ -94,7 +96,7 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
// BungeeCord IP forwarding is simply a special injection after the "address" in the handshake, // BungeeCord IP forwarding is simply a special injection after the "address" in the handshake,
// separated by \0 (the null byte). In order, you send the original host, the player's IP, their // separated by \0 (the null byte). In order, you send the original host, the player's IP, their
// UUID (undashed), and if you are in online-mode, their login properties (retrieved from Mojang). // UUID (undashed), and if you are in online-mode, their login properties (retrieved from Mojang).
return serverInfo.getAddress().getHostString() + "\0" + return registeredServer.getServerInfo().getAddress().getHostString() + "\0" +
proxyPlayer.getRemoteAddress().getHostString() + "\0" + proxyPlayer.getRemoteAddress().getHostString() + "\0" +
proxyPlayer.getProfile().getId() + "\0" + proxyPlayer.getProfile().getId() + "\0" +
GSON.toJson(proxyPlayer.getProfile().getProperties()); GSON.toJson(proxyPlayer.getProfile().getProperties());
@ -112,9 +114,9 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
} else if (proxyPlayer.getConnection().isLegacyForge()) { } else if (proxyPlayer.getConnection().isLegacyForge()) {
handshake.setServerAddress(handshake.getServerAddress() + "\0FML\0"); handshake.setServerAddress(handshake.getServerAddress() + "\0FML\0");
} else { } else {
handshake.setServerAddress(serverInfo.getAddress().getHostString()); handshake.setServerAddress(registeredServer.getServerInfo().getAddress().getHostString());
} }
handshake.setPort(serverInfo.getAddress().getPort()); handshake.setPort(registeredServer.getServerInfo().getAddress().getPort());
minecraftConnection.write(handshake); minecraftConnection.write(handshake);
int protocolVersion = proxyPlayer.getConnection().getProtocolVersion(); int protocolVersion = proxyPlayer.getConnection().getProtocolVersion();
@ -136,8 +138,14 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
return minecraftConnection; return minecraftConnection;
} }
@Override
public VelocityRegisteredServer getServer() {
return registeredServer;
}
@Override
public ServerInfo getServerInfo() { public ServerInfo getServerInfo() {
return serverInfo; return registeredServer.getServerInfo();
} }
@Override @Override
@ -155,17 +163,18 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
@Override @Override
public String toString() { public String toString() {
return "[server connection] " + proxyPlayer.getProfile().getName() + " -> " + serverInfo.getName(); return "[server connection] " + proxyPlayer.getProfile().getName() + " -> " + registeredServer.getServerInfo().getName();
} }
@Override @Override
public void sendPluginMessage(ChannelIdentifier identifier, byte[] data) { public boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data) {
Preconditions.checkNotNull(identifier, "identifier"); Preconditions.checkNotNull(identifier, "identifier");
Preconditions.checkNotNull(data, "data"); Preconditions.checkNotNull(data, "data");
PluginMessage message = new PluginMessage(); PluginMessage message = new PluginMessage();
message.setChannel(identifier.getId()); message.setChannel(identifier.getId());
message.setData(data); message.setData(data);
minecraftConnection.write(message); minecraftConnection.write(message);
return true;
} }
public boolean isLegacyForge() { public boolean isLegacyForge() {

Datei anzeigen

@ -11,6 +11,7 @@ import com.velocitypowered.api.proxy.player.PlayerSettings;
import com.velocitypowered.api.proxy.ConnectionRequestBuilder; import com.velocitypowered.api.proxy.ConnectionRequestBuilder;
import com.velocitypowered.api.proxy.ServerConnection; import com.velocitypowered.api.proxy.ServerConnection;
import com.velocitypowered.api.proxy.messages.ChannelIdentifier; import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.util.MessagePosition; import com.velocitypowered.api.util.MessagePosition;
import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.VelocityServer;
@ -24,6 +25,7 @@ import com.velocitypowered.proxy.connection.MinecraftConnection;
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection; import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
import com.velocitypowered.proxy.protocol.packet.ClientSettings; import com.velocitypowered.proxy.protocol.packet.ClientSettings;
import com.velocitypowered.proxy.protocol.packet.PluginMessage; import com.velocitypowered.proxy.protocol.packet.PluginMessage;
import com.velocitypowered.proxy.server.VelocityRegisteredServer;
import com.velocitypowered.proxy.util.ThrowableUtils; import com.velocitypowered.proxy.util.ThrowableUtils;
import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.api.proxy.server.ServerInfo;
import com.velocitypowered.proxy.protocol.packet.Disconnect; import com.velocitypowered.proxy.protocol.packet.Disconnect;
@ -159,8 +161,8 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
} }
@Override @Override
public ConnectionRequestBuilder createConnectionRequest(@NonNull ServerInfo info) { public ConnectionRequestBuilder createConnectionRequest(@NonNull RegisteredServer server) {
return new ConnectionRequestBuilderImpl(info); return new ConnectionRequestBuilderImpl(server);
} }
@Override @Override
@ -184,57 +186,57 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
return connectedServer; return connectedServer;
} }
public void handleConnectionException(ServerInfo info, Throwable throwable) { public void handleConnectionException(RegisteredServer server, Throwable throwable) {
String error = ThrowableUtils.briefDescription(throwable); String error = ThrowableUtils.briefDescription(throwable);
String userMessage; String userMessage;
if (connectedServer != null && connectedServer.getServerInfo().equals(info)) { if (connectedServer != null && connectedServer.getServerInfo().equals(server.getServerInfo())) {
userMessage = "Exception in server " + info.getName(); userMessage = "Exception in server " + server.getServerInfo().getName();
} else { } else {
logger.error("{}: unable to connect to server {}", this, info.getName(), throwable); logger.error("{}: unable to connect to server {}", this, server.getServerInfo().getName(), throwable);
userMessage = "Exception connecting to server " + info.getName(); userMessage = "Exception connecting to server " + server.getServerInfo().getName();
} }
handleConnectionException(info, null, TextComponent.builder() handleConnectionException(server, null, TextComponent.builder()
.content(userMessage + ": ") .content(userMessage + ": ")
.color(TextColor.RED) .color(TextColor.RED)
.append(TextComponent.of(error, TextColor.WHITE)) .append(TextComponent.of(error, TextColor.WHITE))
.build()); .build());
} }
public void handleConnectionException(ServerInfo info, Disconnect disconnect) { public void handleConnectionException(RegisteredServer server, Disconnect disconnect) {
Component disconnectReason = ComponentSerializers.JSON.deserialize(disconnect.getReason()); Component disconnectReason = ComponentSerializers.JSON.deserialize(disconnect.getReason());
String plainTextReason = PASS_THRU_TRANSLATE.serialize(disconnectReason); String plainTextReason = PASS_THRU_TRANSLATE.serialize(disconnectReason);
if (connectedServer != null && connectedServer.getServerInfo().equals(info)) { if (connectedServer != null && connectedServer.getServerInfo().equals(server.getServerInfo())) {
logger.error("{}: kicked from server {}: {}", this, info.getName(), plainTextReason); logger.error("{}: kicked from server {}: {}", this, server.getServerInfo().getName(), plainTextReason);
handleConnectionException(info, disconnectReason, TextComponent.builder() handleConnectionException(server, disconnectReason, TextComponent.builder()
.content("Kicked from " + info.getName() + ": ") .content("Kicked from " + server.getServerInfo().getName() + ": ")
.color(TextColor.RED) .color(TextColor.RED)
.append(disconnectReason) .append(disconnectReason)
.build()); .build());
} else { } else {
logger.error("{}: disconnected while connecting to {}: {}", this, info.getName(), plainTextReason); logger.error("{}: disconnected while connecting to {}: {}", this, server.getServerInfo().getName(), plainTextReason);
handleConnectionException(info, disconnectReason, TextComponent.builder() handleConnectionException(server, disconnectReason, TextComponent.builder()
.content("Unable to connect to " + info.getName() + ": ") .content("Unable to connect to " + server.getServerInfo().getName() + ": ")
.color(TextColor.RED) .color(TextColor.RED)
.append(disconnectReason) .append(disconnectReason)
.build()); .build());
} }
} }
private void handleConnectionException(ServerInfo info, @Nullable Component kickReason, Component friendlyReason) { private void handleConnectionException(RegisteredServer rs, @Nullable Component kickReason, Component friendlyReason) {
boolean alreadyConnected = connectedServer != null && connectedServer.getServerInfo().equals(info);; boolean alreadyConnected = connectedServer != null && connectedServer.getServerInfo().equals(rs.getServerInfo());
connectionInFlight = null; connectionInFlight = null;
if (connectedServer == null) { if (connectedServer == null) {
// The player isn't yet connected to a server. // The player isn't yet connected to a server.
Optional<ServerInfo> nextServer = getNextServerToTry(); Optional<RegisteredServer> nextServer = getNextServerToTry();
if (nextServer.isPresent()) { if (nextServer.isPresent()) {
createConnectionRequest(nextServer.get()).fireAndForget(); createConnectionRequest(nextServer.get()).fireAndForget();
} else { } else {
connection.closeWith(Disconnect.create(friendlyReason)); connection.closeWith(Disconnect.create(friendlyReason));
} }
} else if (connectedServer.getServerInfo().equals(info)) { } else if (connectedServer.getServerInfo().equals(rs.getServerInfo())) {
// Already connected to the server being disconnected from. // Already connected to the server being disconnected from.
if (kickReason != null) { if (kickReason != null) {
server.getEventManager().fire(new KickedFromServerEvent(this, info, kickReason, !alreadyConnected, friendlyReason)) server.getEventManager().fire(new KickedFromServerEvent(this, rs, kickReason, !alreadyConnected, friendlyReason))
.thenAcceptAsync(event -> { .thenAcceptAsync(event -> {
if (event.getResult() instanceof KickedFromServerEvent.DisconnectPlayer) { if (event.getResult() instanceof KickedFromServerEvent.DisconnectPlayer) {
KickedFromServerEvent.DisconnectPlayer res = (KickedFromServerEvent.DisconnectPlayer) event.getResult(); KickedFromServerEvent.DisconnectPlayer res = (KickedFromServerEvent.DisconnectPlayer) event.getResult();
@ -255,7 +257,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
} }
} }
Optional<ServerInfo> getNextServerToTry() { Optional<RegisteredServer> getNextServerToTry() {
List<String> serversToTry = server.getConfiguration().getAttemptConnectionOrder(); List<String> serversToTry = server.getConfiguration().getAttemptConnectionOrder();
if (tryIndex >= serversToTry.size()) { if (tryIndex >= serversToTry.size()) {
return Optional.empty(); return Optional.empty();
@ -289,7 +291,9 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
); );
} }
return new VelocityServerConnection(newEvent.getResult().getServer().get(), this, server).connect(); RegisteredServer rs = newEvent.getResult().getServer().get();
Preconditions.checkState(rs instanceof VelocityRegisteredServer, "Not a valid Velocity server.");
return new VelocityServerConnection((VelocityRegisteredServer) rs, this, server).connect();
}); });
} }
@ -335,25 +339,26 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
} }
@Override @Override
public void sendPluginMessage(ChannelIdentifier identifier, byte[] data) { public boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data) {
Preconditions.checkNotNull(identifier, "identifier"); Preconditions.checkNotNull(identifier, "identifier");
Preconditions.checkNotNull(data, "data"); Preconditions.checkNotNull(data, "data");
PluginMessage message = new PluginMessage(); PluginMessage message = new PluginMessage();
message.setChannel(identifier.getId()); message.setChannel(identifier.getId());
message.setData(data); message.setData(data);
connection.write(message); connection.write(message);
return true;
} }
private class ConnectionRequestBuilderImpl implements ConnectionRequestBuilder { private class ConnectionRequestBuilderImpl implements ConnectionRequestBuilder {
private final ServerInfo info; private final RegisteredServer server;
ConnectionRequestBuilderImpl(ServerInfo info) { ConnectionRequestBuilderImpl(RegisteredServer server) {
this.info = Preconditions.checkNotNull(info, "info"); this.server = Preconditions.checkNotNull(server, "info");
} }
@Override @Override
public ServerInfo getServer() { public RegisteredServer getServer() {
return info; return server;
} }
@Override @Override
@ -366,7 +371,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
connect() connect()
.whenCompleteAsync((status, throwable) -> { .whenCompleteAsync((status, throwable) -> {
if (throwable != null) { if (throwable != null) {
handleConnectionException(info, throwable); handleConnectionException(server, throwable);
return; return;
} }
@ -381,7 +386,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
// Ignored; the plugin probably already handled this. // Ignored; the plugin probably already handled this.
break; break;
case SERVER_DISCONNECTED: case SERVER_DISCONNECTED:
handleConnectionException(info, Disconnect.create(status.getReason().orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR))); handleConnectionException(server, Disconnect.create(status.getReason().orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR)));
break; break;
} }
}, connection.getChannel().eventLoop()); }, connection.getChannel().eventLoop());

Datei anzeigen

@ -8,6 +8,7 @@ import com.velocitypowered.api.event.connection.PreLoginEvent.PreLoginComponentR
import com.velocitypowered.api.event.permission.PermissionsSetupEvent; import com.velocitypowered.api.event.permission.PermissionsSetupEvent;
import com.velocitypowered.api.event.player.GameProfileRequestEvent; import com.velocitypowered.api.event.player.GameProfileRequestEvent;
import com.velocitypowered.api.proxy.InboundConnection; import com.velocitypowered.api.proxy.InboundConnection;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.api.proxy.server.ServerInfo;
import com.velocitypowered.proxy.config.PlayerInfoForwarding; import com.velocitypowered.proxy.config.PlayerInfoForwarding;
import com.velocitypowered.proxy.connection.VelocityConstants; import com.velocitypowered.proxy.connection.VelocityConstants;
@ -220,7 +221,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
} }
private void handleProxyLogin(ConnectedPlayer player) { private void handleProxyLogin(ConnectedPlayer player) {
Optional<ServerInfo> toTry = player.getNextServerToTry(); Optional<RegisteredServer> toTry = player.getNextServerToTry();
if (!toTry.isPresent()) { if (!toTry.isPresent()) {
player.close(TextComponent.of("No available servers", TextColor.RED)); player.close(TextComponent.of("No available servers", TextColor.RED));
return; return;
@ -246,9 +247,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
logger.info("{} has connected", player); logger.info("{} has connected", player);
inbound.setSessionHandler(new InitialConnectSessionHandler(player)); inbound.setSessionHandler(new InitialConnectSessionHandler(player));
server.getEventManager().fire(new PostLoginEvent(player)).thenRun(() -> { server.getEventManager().fire(new PostLoginEvent(player)).thenRun(() -> player.createConnectionRequest(toTry.get()).fireAndForget());
player.createConnectionRequest(toTry.get()).fireAndForget();
});
} }
@Override @Override

Datei anzeigen

@ -0,0 +1,68 @@
package com.velocitypowered.proxy.server;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerInfo;
import com.velocitypowered.proxy.VelocityServer;
import java.util.*;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ServerMap {
private final VelocityServer server;
private final Map<String, RegisteredServer> servers = new HashMap<>();
private final ReadWriteLock lock = new ReentrantReadWriteLock();
public ServerMap(VelocityServer server) {
this.server = server;
}
public Optional<RegisteredServer> getServer(String name) {
Preconditions.checkNotNull(name, "server");
String lowerName = name.toLowerCase(Locale.US);
lock.readLock().lock();
try {
return Optional.ofNullable(servers.get(lowerName));
} finally {
lock.readLock().unlock();
}
}
public Collection<RegisteredServer> getAllServers() {
lock.readLock().lock();
try {
return ImmutableList.copyOf(servers.values());
} finally {
lock.readLock().unlock();
}
}
public RegisteredServer register(ServerInfo serverInfo) {
Preconditions.checkNotNull(serverInfo, "serverInfo");
String lowerName = serverInfo.getName().toLowerCase(Locale.US);
lock.writeLock().lock();
try {
VelocityRegisteredServer rs = new VelocityRegisteredServer(server, serverInfo);
Preconditions.checkArgument(servers.putIfAbsent(lowerName, rs) == null, "Server with name %s already registered", serverInfo.getName());
return rs;
} finally {
lock.writeLock().unlock();
}
}
public void unregister(ServerInfo serverInfo) {
Preconditions.checkNotNull(serverInfo, "serverInfo");
String lowerName = serverInfo.getName().toLowerCase(Locale.US);
lock.writeLock().lock();
try {
RegisteredServer rs = servers.get(lowerName);
Preconditions.checkArgument(rs != null, "Server with name %s is not registered!", serverInfo.getName());
Preconditions.checkArgument(rs.getServerInfo().equals(serverInfo), "Trying to remove server %s with differing information", serverInfo.getName());
servers.remove(lowerName);
} finally {
lock.writeLock().unlock();
}
}
}

Datei anzeigen

@ -0,0 +1,95 @@
package com.velocitypowered.proxy.server;
import com.google.common.collect.ImmutableList;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ServerConnection;
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerInfo;
import com.velocitypowered.api.proxy.server.ServerPing;
import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class VelocityRegisteredServer implements RegisteredServer {
private final VelocityServer server;
private final ServerInfo serverInfo;
private final Set<ConnectedPlayer> players = new HashSet<>();
private final ReadWriteLock playersLock = new ReentrantReadWriteLock();
public VelocityRegisteredServer(VelocityServer server, ServerInfo serverInfo) {
this.server = server;
this.serverInfo = serverInfo;
}
@Override
public ServerInfo getServerInfo() {
return serverInfo;
}
@Override
public Collection<Player> getPlayersConnected() {
playersLock.readLock().lock();
try {
return ImmutableList.copyOf(players);
} finally {
playersLock.readLock().unlock();
}
}
@Override
public CompletableFuture<ServerPing> ping() {
CompletableFuture<ServerPing> p = new CompletableFuture<>();
p.completeExceptionally(new UnsupportedOperationException("Not currently implemented."));
return p;
}
public void addPlayer(ConnectedPlayer player) {
playersLock.writeLock().lock();
try {
players.add(player);
} finally {
playersLock.writeLock().unlock();
}
}
public void removePlayer(ConnectedPlayer player) {
playersLock.writeLock().lock();
try {
players.remove(player);
} finally {
playersLock.writeLock().unlock();
}
}
@Override
public boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data) {
ServerConnection backendConnection = null;
playersLock.readLock().lock();
try {
for (ConnectedPlayer player : players) {
if (player.getConnectedServer() != null && player.getConnectedServer().getServerInfo().equals(serverInfo)) {
backendConnection = player.getConnectedServer();
break;
}
}
if (backendConnection == null) {
return false;
}
} finally {
playersLock.readLock().unlock();
}
return backendConnection.sendPluginMessage(identifier, data);
}
@Override
public String toString() {
return "registered server: " + serverInfo;
}
}

Datei anzeigen

@ -1,56 +0,0 @@
package com.velocitypowered.proxy.util;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.velocitypowered.api.proxy.server.ServerInfo;
import java.util.*;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ServerMap {
private final Map<String, ServerInfo> servers = new HashMap<>();
private final ReadWriteLock lock = new ReentrantReadWriteLock();
public Optional<ServerInfo> getServer(String server) {
Preconditions.checkNotNull(server, "server");
String lowerName = server.toLowerCase(Locale.US);
lock.readLock().lock();
try {
return Optional.ofNullable(servers.get(lowerName));
} finally {
lock.readLock().unlock();
}
}
public Collection<ServerInfo> getAllServers() {
lock.readLock().lock();
try {
return ImmutableList.copyOf(servers.values());
} finally {
lock.readLock().unlock();
}
}
public void register(ServerInfo server) {
Preconditions.checkNotNull(server, "server");
String lowerName = server.getName().toLowerCase(Locale.US);
lock.writeLock().lock();
try {
Preconditions.checkArgument(servers.putIfAbsent(lowerName, server) == null, "Server with name %s already registered", server.getName());
} finally {
lock.writeLock().unlock();
}
}
public void unregister(ServerInfo server) {
Preconditions.checkNotNull(server, "server");
String lowerName = server.getName().toLowerCase(Locale.US);
lock.writeLock().lock();
try {
Preconditions.checkArgument(servers.remove(lowerName, server), "Server with this name is not registered!");
} finally {
lock.writeLock().unlock();
}
}
}

Datei anzeigen

@ -1,6 +1,8 @@
package com.velocitypowered.proxy.util; package com.velocitypowered.proxy.util;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.api.proxy.server.ServerInfo;
import com.velocitypowered.proxy.server.ServerMap;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.net.InetAddress; import java.net.InetAddress;
@ -14,18 +16,18 @@ class ServerMapTest {
@Test @Test
void respectsCaseInsensitivity() { void respectsCaseInsensitivity() {
ServerMap map = new ServerMap(); ServerMap map = new ServerMap(null);
ServerInfo info = new ServerInfo("TestServer", TEST_ADDRESS); ServerInfo info = new ServerInfo("TestServer", TEST_ADDRESS);
map.register(info); RegisteredServer connection = map.register(info);
assertEquals(Optional.of(info), map.getServer("TestServer")); assertEquals(Optional.of(connection), map.getServer("TestServer"));
assertEquals(Optional.of(info), map.getServer("testserver")); assertEquals(Optional.of(connection), map.getServer("testserver"));
assertEquals(Optional.of(info), map.getServer("TESTSERVER")); assertEquals(Optional.of(connection), map.getServer("TESTSERVER"));
} }
@Test @Test
void rejectsRepeatedRegisterAttempts() { void rejectsRepeatedRegisterAttempts() {
ServerMap map = new ServerMap(); ServerMap map = new ServerMap(null);
ServerInfo info = new ServerInfo("TestServer", TEST_ADDRESS); ServerInfo info = new ServerInfo("TestServer", TEST_ADDRESS);
map.register(info); map.register(info);