Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-12-25 07:40:13 +01:00
Merge pull request #240 from VelocityPowered/feature/ping-passthrough
Ping passthrough
Dieser Commit ist enthalten in:
Commit
2c3b30fff2
@ -182,6 +182,19 @@ public final class ServerPing {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses the modified {@code mods} list in the response.
|
||||||
|
* @param mods the mods list to use
|
||||||
|
* @return this build, for chaining
|
||||||
|
*/
|
||||||
|
public Builder mods(ModInfo mods) {
|
||||||
|
Preconditions.checkNotNull(mods, "mods");
|
||||||
|
this.modType = mods.getType();
|
||||||
|
this.mods.clear();
|
||||||
|
this.mods.addAll(mods.getMods());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Builder clearMods() {
|
public Builder clearMods() {
|
||||||
this.mods.clear();
|
this.mods.clear();
|
||||||
return this;
|
return this;
|
||||||
|
@ -67,6 +67,8 @@ dependencies {
|
|||||||
|
|
||||||
compile 'org.asynchttpclient:async-http-client:2.10.1'
|
compile 'org.asynchttpclient:async-http-client:2.10.1'
|
||||||
|
|
||||||
|
compile 'com.spotify:completable-futures:0.3.2'
|
||||||
|
|
||||||
testCompile "org.junit.jupiter:junit-jupiter-api:${junitVersion}"
|
testCompile "org.junit.jupiter:junit-jupiter-api:${junitVersion}"
|
||||||
testCompile "org.junit.jupiter:junit-jupiter-engine:${junitVersion}"
|
testCompile "org.junit.jupiter:junit-jupiter-engine:${junitVersion}"
|
||||||
}
|
}
|
||||||
|
@ -77,6 +77,7 @@ import org.asynchttpclient.AsyncHttpClient;
|
|||||||
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
|
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
|
||||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
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.RequiresNonNull;
|
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||||
|
|
||||||
public class VelocityServer implements ProxyServer {
|
public class VelocityServer implements ProxyServer {
|
||||||
@ -263,11 +264,7 @@ public class VelocityServer implements ProxyServer {
|
|||||||
logger.info("Loaded {} plugins", pluginManager.getPlugins().size());
|
logger.info("Loaded {} plugins", pluginManager.getPlugins().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bootstrap createBootstrap() {
|
public Bootstrap createBootstrap(@Nullable EventLoopGroup group) {
|
||||||
return this.cm.createWorker();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bootstrap createBootstrap(EventLoopGroup group) {
|
|
||||||
return this.cm.createWorker(group);
|
return this.cm.createWorker(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.velocitypowered.proxy.config;
|
||||||
|
|
||||||
|
public enum PingPassthroughMode {
|
||||||
|
DISABLED,
|
||||||
|
MODS,
|
||||||
|
ALL
|
||||||
|
}
|
@ -72,8 +72,13 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
|
|||||||
@ConfigKey("forwarding-secret")
|
@ConfigKey("forwarding-secret")
|
||||||
private byte[] forwardingSecret = generateRandomString(12).getBytes(StandardCharsets.UTF_8);
|
private byte[] forwardingSecret = generateRandomString(12).getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
@Comment({"Announce whether or not your server supports Forge. If you run a modded server, we",
|
@Comment({
|
||||||
"suggest turning this on."})
|
"Announce whether or not your server supports Forge. If you run a modded server, we",
|
||||||
|
"suggest turning this on.",
|
||||||
|
"",
|
||||||
|
"If your network runs one modpack consistently, consider using ping-passthrough = \"mods\"",
|
||||||
|
"instead for a nicer display in the server list."
|
||||||
|
})
|
||||||
@ConfigKey("announce-forge")
|
@ConfigKey("announce-forge")
|
||||||
private boolean announceForge = false;
|
private boolean announceForge = false;
|
||||||
|
|
||||||
@ -82,6 +87,21 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
|
|||||||
@ConfigKey("kick-existing-players")
|
@ConfigKey("kick-existing-players")
|
||||||
private boolean onlineModeKickExistingPlayers = false;
|
private boolean onlineModeKickExistingPlayers = false;
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"Should Velocity pass server list ping requests to a backend server?",
|
||||||
|
"Available options:",
|
||||||
|
"- \"disabled\": No pass-through will be done. The velocity.toml and server-icon.png",
|
||||||
|
" will determine the initial server list ping response.",
|
||||||
|
"- \"mods\": Passes only the mod list from your backend server into the response.",
|
||||||
|
" The first server in your try list (or forced host) with a mod list will be",
|
||||||
|
" used. If no backend servers can be contacted, Velocity will not display any",
|
||||||
|
" mod information.",
|
||||||
|
"- \"all\": Passes everything from the backend server into the response. The Velocity",
|
||||||
|
" configuration is used if no servers could be contacted."
|
||||||
|
})
|
||||||
|
@ConfigKey("ping-passthrough")
|
||||||
|
private PingPassthroughMode pingPassthrough;
|
||||||
|
|
||||||
@Table("[servers]")
|
@Table("[servers]")
|
||||||
private final Servers servers;
|
private final Servers servers;
|
||||||
|
|
||||||
@ -114,8 +134,8 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
|
|||||||
|
|
||||||
private VelocityConfiguration(String bind, String motd, int showMaxPlayers, boolean onlineMode,
|
private VelocityConfiguration(String bind, String motd, int showMaxPlayers, boolean onlineMode,
|
||||||
boolean announceForge, PlayerInfoForwarding playerInfoForwardingMode, byte[] forwardingSecret,
|
boolean announceForge, PlayerInfoForwarding playerInfoForwardingMode, byte[] forwardingSecret,
|
||||||
boolean onlineModeKickExistingPlayers, Servers servers, ForcedHosts forcedHosts,
|
boolean onlineModeKickExistingPlayers, PingPassthroughMode pingPassthrough, Servers servers,
|
||||||
Advanced advanced, Query query, Metrics metrics) {
|
ForcedHosts forcedHosts, Advanced advanced, Query query, Metrics metrics) {
|
||||||
this.bind = bind;
|
this.bind = bind;
|
||||||
this.motd = motd;
|
this.motd = motd;
|
||||||
this.showMaxPlayers = showMaxPlayers;
|
this.showMaxPlayers = showMaxPlayers;
|
||||||
@ -124,6 +144,7 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
|
|||||||
this.playerInfoForwardingMode = playerInfoForwardingMode;
|
this.playerInfoForwardingMode = playerInfoForwardingMode;
|
||||||
this.forwardingSecret = forwardingSecret;
|
this.forwardingSecret = forwardingSecret;
|
||||||
this.onlineModeKickExistingPlayers = onlineModeKickExistingPlayers;
|
this.onlineModeKickExistingPlayers = onlineModeKickExistingPlayers;
|
||||||
|
this.pingPassthrough = pingPassthrough;
|
||||||
this.servers = servers;
|
this.servers = servers;
|
||||||
this.forcedHosts = forcedHosts;
|
this.forcedHosts = forcedHosts;
|
||||||
this.advanced = advanced;
|
this.advanced = advanced;
|
||||||
@ -380,6 +401,10 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
|
|||||||
return metrics;
|
return metrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PingPassthroughMode getPingPassthrough() {
|
||||||
|
return pingPassthrough;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return MoreObjects.toStringHelper(this)
|
return MoreObjects.toStringHelper(this)
|
||||||
@ -427,6 +452,8 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
|
|||||||
|
|
||||||
String forwardingModeName = toml.getString("player-info-forwarding-mode", "MODERN")
|
String forwardingModeName = toml.getString("player-info-forwarding-mode", "MODERN")
|
||||||
.toUpperCase(Locale.US);
|
.toUpperCase(Locale.US);
|
||||||
|
String passThroughName = toml.getString("ping-passthrough", "DISABLED")
|
||||||
|
.toUpperCase(Locale.US);
|
||||||
|
|
||||||
return new VelocityConfiguration(
|
return new VelocityConfiguration(
|
||||||
toml.getString("bind", "0.0.0.0:25577"),
|
toml.getString("bind", "0.0.0.0:25577"),
|
||||||
@ -437,6 +464,7 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
|
|||||||
PlayerInfoForwarding.valueOf(forwardingModeName),
|
PlayerInfoForwarding.valueOf(forwardingModeName),
|
||||||
forwardingSecret,
|
forwardingSecret,
|
||||||
toml.getBoolean("kick-existing-players", false),
|
toml.getBoolean("kick-existing-players", false),
|
||||||
|
PingPassthroughMode.valueOf(passThroughName),
|
||||||
servers,
|
servers,
|
||||||
forcedHosts,
|
forcedHosts,
|
||||||
advanced,
|
advanced,
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
package com.velocitypowered.proxy.connection.client;
|
package com.velocitypowered.proxy.connection.client;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.spotify.futures.CompletableFutures;
|
||||||
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
|
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
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.ServerPing;
|
import com.velocitypowered.api.proxy.server.ServerPing;
|
||||||
import com.velocitypowered.api.util.ModInfo;
|
import com.velocitypowered.api.util.ModInfo;
|
||||||
import com.velocitypowered.proxy.VelocityServer;
|
import com.velocitypowered.proxy.VelocityServer;
|
||||||
|
import com.velocitypowered.proxy.config.PingPassthroughMode;
|
||||||
import com.velocitypowered.proxy.config.VelocityConfiguration;
|
import com.velocitypowered.proxy.config.VelocityConfiguration;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
@ -15,27 +18,32 @@ import com.velocitypowered.proxy.protocol.packet.LegacyPing;
|
|||||||
import com.velocitypowered.proxy.protocol.packet.StatusPing;
|
import com.velocitypowered.proxy.protocol.packet.StatusPing;
|
||||||
import com.velocitypowered.proxy.protocol.packet.StatusRequest;
|
import com.velocitypowered.proxy.protocol.packet.StatusRequest;
|
||||||
import com.velocitypowered.proxy.protocol.packet.StatusResponse;
|
import com.velocitypowered.proxy.protocol.packet.StatusResponse;
|
||||||
|
import com.velocitypowered.proxy.server.VelocityRegisteredServer;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
public class StatusSessionHandler implements MinecraftSessionHandler {
|
public class StatusSessionHandler implements MinecraftSessionHandler {
|
||||||
|
|
||||||
private final VelocityServer server;
|
private final VelocityServer server;
|
||||||
private final MinecraftConnection connection;
|
private final MinecraftConnection connection;
|
||||||
private final InboundConnection inboundWrapper;
|
private final InboundConnection inbound;
|
||||||
|
|
||||||
StatusSessionHandler(VelocityServer server, MinecraftConnection connection,
|
StatusSessionHandler(VelocityServer server, MinecraftConnection connection,
|
||||||
InboundConnection inboundWrapper) {
|
InboundConnection inbound) {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
this.inboundWrapper = inboundWrapper;
|
this.inbound = inbound;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServerPing createInitialPing() {
|
private ServerPing constructLocalPing(ProtocolVersion version) {
|
||||||
VelocityConfiguration configuration = server.getConfiguration();
|
VelocityConfiguration configuration = server.getConfiguration();
|
||||||
ProtocolVersion shownVersion = ProtocolVersion.isSupported(connection.getProtocolVersion())
|
|
||||||
? connection.getProtocolVersion() : ProtocolVersion.MAXIMUM_VERSION;
|
|
||||||
return new ServerPing(
|
return new ServerPing(
|
||||||
new ServerPing.Version(shownVersion.getProtocol(),
|
new ServerPing.Version(version.getProtocol(),
|
||||||
"Velocity " + ProtocolVersion.SUPPORTED_VERSION_STRING),
|
"Velocity " + ProtocolVersion.SUPPORTED_VERSION_STRING),
|
||||||
new ServerPing.Players(server.getPlayerCount(), configuration.getShowMaxPlayers(),
|
new ServerPing.Players(server.getPlayerCount(), configuration.getShowMaxPlayers(),
|
||||||
ImmutableList.of()),
|
ImmutableList.of()),
|
||||||
@ -45,12 +53,78 @@ public class StatusSessionHandler implements MinecraftSessionHandler {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CompletableFuture<ServerPing> attemptPingPassthrough(PingPassthroughMode mode,
|
||||||
|
List<String> servers, ProtocolVersion pingingVersion) {
|
||||||
|
ServerPing fallback = constructLocalPing(pingingVersion);
|
||||||
|
List<CompletableFuture<ServerPing>> pings = new ArrayList<>();
|
||||||
|
for (String s : servers) {
|
||||||
|
Optional<RegisteredServer> rs = server.getServer(s);
|
||||||
|
if (!rs.isPresent()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
VelocityRegisteredServer vrs = (VelocityRegisteredServer) rs.get();
|
||||||
|
pings.add(vrs.ping(connection.eventLoop(), pingingVersion));
|
||||||
|
}
|
||||||
|
if (pings.isEmpty()) {
|
||||||
|
return CompletableFuture.completedFuture(fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
CompletableFuture<List<ServerPing>> pingResponses = CompletableFutures.successfulAsList(pings,
|
||||||
|
(ex) -> fallback);
|
||||||
|
switch (mode) {
|
||||||
|
case ALL:
|
||||||
|
return pingResponses.thenApply(responses -> {
|
||||||
|
// Find the first non-fallback
|
||||||
|
for (ServerPing response : responses) {
|
||||||
|
if (response == fallback) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
return fallback;
|
||||||
|
});
|
||||||
|
case MODS:
|
||||||
|
return pingResponses.thenApply(responses -> {
|
||||||
|
// Find the first non-fallback that contains a mod list
|
||||||
|
for (ServerPing response : responses) {
|
||||||
|
if (response == fallback) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Optional<ModInfo> modInfo = response.getModinfo();
|
||||||
|
if (modInfo.isPresent()) {
|
||||||
|
return fallback.asBuilder().mods(modInfo.get()).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fallback;
|
||||||
|
});
|
||||||
|
default:
|
||||||
|
// Not possible, but covered for completeness.
|
||||||
|
return CompletableFuture.completedFuture(fallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CompletableFuture<ServerPing> getInitialPing() {
|
||||||
|
VelocityConfiguration configuration = server.getConfiguration();
|
||||||
|
ProtocolVersion shownVersion = ProtocolVersion.isSupported(connection.getProtocolVersion())
|
||||||
|
? connection.getProtocolVersion() : ProtocolVersion.MAXIMUM_VERSION;
|
||||||
|
PingPassthroughMode passthrough = configuration.getPingPassthrough();
|
||||||
|
|
||||||
|
if (passthrough == PingPassthroughMode.DISABLED) {
|
||||||
|
return CompletableFuture.completedFuture(constructLocalPing(shownVersion));
|
||||||
|
} else {
|
||||||
|
String virtualHostStr = inbound.getVirtualHost().map(InetSocketAddress::getHostString)
|
||||||
|
.orElse("");
|
||||||
|
List<String> serversToTry = server.getConfiguration().getForcedHosts().getOrDefault(
|
||||||
|
virtualHostStr, server.getConfiguration().getAttemptConnectionOrder());
|
||||||
|
return attemptPingPassthrough(configuration.getPingPassthrough(), serversToTry, shownVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(LegacyPing packet) {
|
public boolean handle(LegacyPing packet) {
|
||||||
ServerPing initialPing = createInitialPing();
|
getInitialPing()
|
||||||
ProxyPingEvent event = new ProxyPingEvent(inboundWrapper, initialPing);
|
.thenCompose(ping -> server.getEventManager().fire(new ProxyPingEvent(inbound, ping)))
|
||||||
server.getEventManager().fire(event)
|
.thenAcceptAsync(event -> {
|
||||||
.thenRunAsync(() -> {
|
|
||||||
connection.closeWith(LegacyDisconnect.fromServerPing(event.getPing(),
|
connection.closeWith(LegacyDisconnect.fromServerPing(event.getPing(),
|
||||||
packet.getVersion()));
|
packet.getVersion()));
|
||||||
}, connection.eventLoop());
|
}, connection.eventLoop());
|
||||||
@ -65,11 +139,10 @@ public class StatusSessionHandler implements MinecraftSessionHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(StatusRequest packet) {
|
public boolean handle(StatusRequest packet) {
|
||||||
ServerPing initialPing = createInitialPing();
|
getInitialPing()
|
||||||
ProxyPingEvent event = new ProxyPingEvent(inboundWrapper, initialPing);
|
.thenCompose(ping -> server.getEventManager().fire(new ProxyPingEvent(inbound, ping)))
|
||||||
server.getEventManager().fire(event)
|
.thenAcceptAsync(
|
||||||
.thenRunAsync(
|
(event) -> {
|
||||||
() -> {
|
|
||||||
StringBuilder json = new StringBuilder();
|
StringBuilder json = new StringBuilder();
|
||||||
VelocityServer.GSON.toJson(event.getPing(), json);
|
VelocityServer.GSON.toJson(event.getPing(), json);
|
||||||
connection.write(new StatusResponse(json));
|
connection.write(new StatusResponse(json));
|
||||||
|
@ -145,10 +145,6 @@ public final class ConnectionManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bootstrap createWorker() {
|
|
||||||
return this.createWorker(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a TCP {@link Bootstrap} using Velocity's event loops.
|
* Creates a TCP {@link Bootstrap} using Velocity's event loops.
|
||||||
*
|
*
|
||||||
|
@ -18,13 +18,15 @@ public class PingSessionHandler implements MinecraftSessionHandler {
|
|||||||
private final CompletableFuture<ServerPing> result;
|
private final CompletableFuture<ServerPing> result;
|
||||||
private final RegisteredServer server;
|
private final RegisteredServer server;
|
||||||
private final MinecraftConnection connection;
|
private final MinecraftConnection connection;
|
||||||
|
private final ProtocolVersion version;
|
||||||
private boolean completed = false;
|
private boolean completed = false;
|
||||||
|
|
||||||
PingSessionHandler(CompletableFuture<ServerPing> result, RegisteredServer server,
|
PingSessionHandler(CompletableFuture<ServerPing> result, RegisteredServer server,
|
||||||
MinecraftConnection connection) {
|
MinecraftConnection connection, ProtocolVersion version) {
|
||||||
this.result = result;
|
this.result = result;
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
|
this.version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -33,7 +35,7 @@ public class PingSessionHandler implements MinecraftSessionHandler {
|
|||||||
handshake.setNextStatus(StateRegistry.STATUS_ID);
|
handshake.setNextStatus(StateRegistry.STATUS_ID);
|
||||||
handshake.setServerAddress(server.getServerInfo().getAddress().getHostString());
|
handshake.setServerAddress(server.getServerInfo().getAddress().getHostString());
|
||||||
handshake.setPort(server.getServerInfo().getAddress().getPort());
|
handshake.setPort(server.getServerInfo().getAddress().getPort());
|
||||||
handshake.setProtocolVersion(ProtocolVersion.MINIMUM_VERSION);
|
handshake.setProtocolVersion(version);
|
||||||
connection.delayedWrite(handshake);
|
connection.delayedWrite(handshake);
|
||||||
|
|
||||||
connection.setState(StateRegistry.STATUS);
|
connection.setState(StateRegistry.STATUS);
|
||||||
|
@ -9,6 +9,7 @@ import static com.velocitypowered.proxy.network.Connections.READ_TIMEOUT;
|
|||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.api.proxy.Player;
|
import com.velocitypowered.api.proxy.Player;
|
||||||
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;
|
||||||
@ -27,6 +28,7 @@ import io.netty.channel.Channel;
|
|||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import io.netty.channel.ChannelFutureListener;
|
import io.netty.channel.ChannelFutureListener;
|
||||||
import io.netty.channel.ChannelInitializer;
|
import io.netty.channel.ChannelInitializer;
|
||||||
|
import io.netty.channel.EventLoop;
|
||||||
import io.netty.handler.timeout.ReadTimeoutHandler;
|
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -58,11 +60,22 @@ public class VelocityRegisteredServer implements RegisteredServer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<ServerPing> ping() {
|
public CompletableFuture<ServerPing> ping() {
|
||||||
|
return ping(null, ProtocolVersion.UNKNOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pings the specified server using the specified event {@code loop}, claiming to be
|
||||||
|
* {@code version}.
|
||||||
|
* @param loop the event loop to use
|
||||||
|
* @param version the version to report
|
||||||
|
* @return the server list ping response
|
||||||
|
*/
|
||||||
|
public CompletableFuture<ServerPing> ping(@Nullable EventLoop loop, ProtocolVersion version) {
|
||||||
if (server == null) {
|
if (server == null) {
|
||||||
throw new IllegalStateException("No Velocity proxy instance available");
|
throw new IllegalStateException("No Velocity proxy instance available");
|
||||||
}
|
}
|
||||||
CompletableFuture<ServerPing> pingFuture = new CompletableFuture<>();
|
CompletableFuture<ServerPing> pingFuture = new CompletableFuture<>();
|
||||||
server.createBootstrap()
|
server.createBootstrap(loop)
|
||||||
.handler(new ChannelInitializer<Channel>() {
|
.handler(new ChannelInitializer<Channel>() {
|
||||||
@Override
|
@Override
|
||||||
protected void initChannel(Channel ch) throws Exception {
|
protected void initChannel(Channel ch) throws Exception {
|
||||||
@ -86,8 +99,8 @@ public class VelocityRegisteredServer implements RegisteredServer {
|
|||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
public void operationComplete(ChannelFuture future) throws Exception {
|
||||||
if (future.isSuccess()) {
|
if (future.isSuccess()) {
|
||||||
MinecraftConnection conn = future.channel().pipeline().get(MinecraftConnection.class);
|
MinecraftConnection conn = future.channel().pipeline().get(MinecraftConnection.class);
|
||||||
conn.setSessionHandler(
|
conn.setSessionHandler(new PingSessionHandler(
|
||||||
new PingSessionHandler(pingFuture, VelocityRegisteredServer.this, conn));
|
pingFuture, VelocityRegisteredServer.this, conn, version));
|
||||||
} else {
|
} else {
|
||||||
pingFuture.completeExceptionally(future.cause());
|
pingFuture.completeExceptionally(future.cause());
|
||||||
}
|
}
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren