geforkt von Mirrors/Velocity
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:
Ursprung
88b7407aaf
Commit
e1b2dc0d43
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
}
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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) {
|
||||||
|
@ -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() {
|
||||||
|
@ -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());
|
||||||
|
@ -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
|
||||||
|
68
proxy/src/main/java/com/velocitypowered/proxy/server/ServerMap.java
Normale Datei
68
proxy/src/main/java/com/velocitypowered/proxy/server/ServerMap.java
Normale Datei
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
||||||
|
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren