3
0
Mirror von https://github.com/PaperMC/Velocity.git synchronisiert 2024-11-16 21:10:30 +01:00

Merge branch 'dev/3.0.0' into dev/resource-packs

Dieser Commit ist enthalten in:
Shane Freeder 2024-01-18 12:09:59 +00:00
Commit c045adf55e
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: A3F61EA5A085289C
7 geänderte Dateien mit 79 neuen und 100 gelöschten Zeilen

Datei anzeigen

@ -15,7 +15,6 @@ spotless = "com.diffplug.spotless:6.12.0"
adventure-bom = "net.kyori:adventure-bom:4.15.0-SNAPSHOT" adventure-bom = "net.kyori:adventure-bom:4.15.0-SNAPSHOT"
adventure-facet = "net.kyori:adventure-platform-facet:4.3.0" adventure-facet = "net.kyori:adventure-platform-facet:4.3.0"
asm = "org.ow2.asm:asm:9.5" asm = "org.ow2.asm:asm:9.5"
asynchttpclient = "org.asynchttpclient:async-http-client:2.12.3"
brigadier = "com.velocitypowered:velocity-brigadier:1.0.0-SNAPSHOT" brigadier = "com.velocitypowered:velocity-brigadier:1.0.0-SNAPSHOT"
bstats = "org.bstats:bstats-base:3.0.1" bstats = "org.bstats:bstats-base:3.0.1"
caffeine = "com.github.ben-manes.caffeine:caffeine:3.1.5" caffeine = "com.github.ben-manes.caffeine:caffeine:3.1.5"

Datei anzeigen

@ -119,7 +119,6 @@ dependencies {
implementation(platform(libs.adventure.bom)) implementation(platform(libs.adventure.bom))
implementation("net.kyori:adventure-nbt") implementation("net.kyori:adventure-nbt")
implementation(libs.adventure.facet) implementation(libs.adventure.facet)
implementation(libs.asynchttpclient)
implementation(libs.completablefutures) implementation(libs.completablefutures)
implementation(libs.nightconfig) implementation(libs.nightconfig)
implementation(libs.bstats) implementation(libs.bstats)

Datei anzeigen

@ -71,6 +71,7 @@ import io.netty.channel.EventLoopGroup;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.http.HttpClient;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.security.AccessController; import java.security.AccessController;
@ -100,7 +101,6 @@ import net.kyori.adventure.translation.GlobalTranslator;
import net.kyori.adventure.translation.TranslationRegistry; import net.kyori.adventure.translation.TranslationRegistry;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
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;
@ -143,6 +143,7 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
private final ConnectionManager cm; private final ConnectionManager cm;
private final ProxyOptions options; private final ProxyOptions options;
private final HttpClient httpClient;
private @MonotonicNonNull VelocityConfiguration configuration; private @MonotonicNonNull VelocityConfiguration configuration;
private @MonotonicNonNull KeyPair serverKeyPair; private @MonotonicNonNull KeyPair serverKeyPair;
private final ServerMap servers; private final ServerMap servers;
@ -168,6 +169,7 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
scheduler = new VelocityScheduler(pluginManager); scheduler = new VelocityScheduler(pluginManager);
console = new VelocityConsole(this); console = new VelocityConsole(this);
cm = new ConnectionManager(this); cm = new ConnectionManager(this);
httpClient = HttpClient.newHttpClient();
servers = new ServerMap(this); servers = new ServerMap(this);
serverListPingHandler = new ServerListPingHandler(this); serverListPingHandler = new ServerListPingHandler(this);
this.options = options; this.options = options;
@ -591,7 +593,7 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
this.cm.closeEndpoints(false); this.cm.closeEndpoints(false);
} }
public AsyncHttpClient getAsyncHttpClient() { public HttpClient getHttpClient() {
return cm.getHttpClient(); return cm.getHttpClient();
} }

Datei anzeigen

@ -106,13 +106,12 @@ import net.kyori.adventure.platform.facet.FacetPointers.Type;
import net.kyori.adventure.pointer.Pointers; import net.kyori.adventure.pointer.Pointers;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import net.kyori.adventure.title.Title.Times; import net.kyori.adventure.title.Title.Times;
import net.kyori.adventure.title.TitlePart; import net.kyori.adventure.title.TitlePart;
import net.kyori.adventure.translation.GlobalTranslator; import net.kyori.adventure.translation.GlobalTranslator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
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.Nullable;
@ -129,7 +128,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
PlainTextComponentSerializer.builder().flattener(TranslatableMapper.FLATTENER).build(); PlainTextComponentSerializer.builder().flattener(TranslatableMapper.FLATTENER).build();
static final PermissionProvider DEFAULT_PERMISSIONS = s -> PermissionFunction.ALWAYS_UNDEFINED; static final PermissionProvider DEFAULT_PERMISSIONS = s -> PermissionFunction.ALWAYS_UNDEFINED;
private static final Logger logger = LogManager.getLogger(ConnectedPlayer.class); private static final ComponentLogger logger = ComponentLogger.logger(ConnectedPlayer.class);
private final Identity identity = new IdentityImpl(); private final Identity identity = new IdentityImpl();
/** /**
@ -588,8 +587,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
Component translated = this.translateMessage(reason); Component translated = this.translateMessage(reason);
if (server.getConfiguration().isLogPlayerConnections()) { if (server.getConfiguration().isLogPlayerConnections()) {
logger.info("{} has disconnected: {}", this, logger.info(Component.text(this + " has disconnected: ").append(translated));
LegacyComponentSerializer.legacySection().serialize(translated));
} }
connection.closeWith(Disconnect.create(translated, this.getProtocolVersion(), duringLogin)); connection.closeWith(Disconnect.create(translated, this.getProtocolVersion(), duringLogin));
} }

Datei anzeigen

@ -29,10 +29,8 @@ import java.net.InetSocketAddress;
import java.util.Locale; import java.util.Locale;
import java.util.Optional; import java.util.Optional;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
import net.kyori.adventure.translation.GlobalTranslator; import net.kyori.adventure.translation.GlobalTranslator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/** /**
* Implements {@link InboundConnection} for a newly-established connection. * Implements {@link InboundConnection} for a newly-established connection.
@ -40,7 +38,8 @@ import org.apache.logging.log4j.Logger;
public final class InitialInboundConnection implements VelocityInboundConnection, public final class InitialInboundConnection implements VelocityInboundConnection,
MinecraftConnectionAssociation { MinecraftConnectionAssociation {
private static final Logger logger = LogManager.getLogger(InitialInboundConnection.class); private static final ComponentLogger logger = ComponentLogger
.logger(InitialInboundConnection.class);
private final MinecraftConnection connection; private final MinecraftConnection connection;
private final String cleanedAddress; private final String cleanedAddress;
@ -97,8 +96,7 @@ public final class InitialInboundConnection implements VelocityInboundConnection
Component translated = GlobalTranslator.render(reason, ClosestLocaleMatcher.INSTANCE Component translated = GlobalTranslator.render(reason, ClosestLocaleMatcher.INSTANCE
.lookupClosest(Locale.getDefault())); .lookupClosest(Locale.getDefault()));
if (connection.server.getConfiguration().isLogPlayerConnections()) { if (connection.server.getConfiguration().isLogPlayerConnections()) {
logger.info("{} has disconnected: {}", this, logger.info(Component.text(this + " has disconnected: ").append(translated));
LegacyComponentSerializer.legacySection().serialize(translated));
} }
connection.closeWith(Disconnect.create(translated, getProtocolVersion(), true)); connection.closeWith(Disconnect.create(translated, getProtocolVersion(), true));
} }

Datei anzeigen

@ -42,19 +42,19 @@ import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse;
import com.velocitypowered.proxy.protocol.packet.ServerLogin; import com.velocitypowered.proxy.protocol.packet.ServerLogin;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.URI;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.util.Arrays; import java.util.Arrays;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.asynchttpclient.ListenableFuture;
import org.asynchttpclient.Response;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** /**
@ -77,7 +77,7 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler {
private boolean forceKeyAuthentication; private boolean forceKeyAuthentication;
InitialLoginSessionHandler(VelocityServer server, MinecraftConnection mcConnection, InitialLoginSessionHandler(VelocityServer server, MinecraftConnection mcConnection,
LoginInboundConnection inbound) { LoginInboundConnection inbound) {
this.server = Preconditions.checkNotNull(server, "server"); this.server = Preconditions.checkNotNull(server, "server");
this.mcConnection = Preconditions.checkNotNull(mcConnection, "mcConnection"); this.mcConnection = Preconditions.checkNotNull(mcConnection, "mcConnection");
this.inbound = Preconditions.checkNotNull(inbound, "inbound"); this.inbound = Preconditions.checkNotNull(inbound, "inbound");
@ -209,63 +209,64 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler {
url += "&ip=" + urlFormParameterEscaper().escape(playerIp); url += "&ip=" + urlFormParameterEscaper().escape(playerIp);
} }
ListenableFuture<Response> hasJoinedResponse = server.getAsyncHttpClient().prepareGet(url) final HttpRequest httpRequest = HttpRequest.newBuilder()
.execute(); .setHeader("User-Agent",
hasJoinedResponse.addListener(() -> { server.getVersion().getName() + "/" + server.getVersion().getVersion())
if (mcConnection.isClosed()) { .uri(URI.create(url))
// The player disconnected after we authenticated them. .build();
return; server.getHttpClient().sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString())
} .whenCompleteAsync((response, throwable) -> {
if (mcConnection.isClosed()) {
// Go ahead and enable encryption. Once the client sends EncryptionResponse, encryption // The player disconnected after we authenticated them.
// is enabled. return;
try {
mcConnection.enableEncryption(decryptedSharedSecret);
} catch (GeneralSecurityException e) {
logger.error("Unable to enable encryption for connection", e);
// At this point, the connection is encrypted, but something's wrong on our side and
// we can't do anything about it.
mcConnection.close(true);
return;
}
try {
Response profileResponse = hasJoinedResponse.get();
if (profileResponse.getStatusCode() == 200) {
final GameProfile profile = GENERAL_GSON.fromJson(profileResponse.getResponseBody(),
GameProfile.class);
// Not so fast, now we verify the public key for 1.19.1+
if (inbound.getIdentifiedKey() != null
&& inbound.getIdentifiedKey().getKeyRevision() == IdentifiedKey.Revision.LINKED_V2
&& inbound.getIdentifiedKey() instanceof IdentifiedKeyImpl) {
IdentifiedKeyImpl key = (IdentifiedKeyImpl) inbound.getIdentifiedKey();
if (!key.internalAddHolder(profile.getId())) {
inbound.disconnect(
Component.translatable("multiplayer.disconnect.invalid_public_key"));
}
} }
// All went well, initialize the session.
mcConnection.setActiveSessionHandler(StateRegistry.LOGIN, if (throwable != null) {
new AuthSessionHandler(server, inbound, profile, true)); logger.error("Unable to authenticate player", throwable);
} else if (profileResponse.getStatusCode() == 204) { inbound.disconnect(Component.translatable("multiplayer.disconnect.authservers_down"));
// Apparently an offline-mode user logged onto this online-mode proxy. return;
inbound.disconnect( }
Component.translatable("velocity.error.online-mode-only", NamedTextColor.RED));
} else { // Go ahead and enable encryption. Once the client sends EncryptionResponse, encryption
// Something else went wrong // is enabled.
logger.error( try {
"Got an unexpected error code {} whilst contacting Mojang to log in {} ({})", mcConnection.enableEncryption(decryptedSharedSecret);
profileResponse.getStatusCode(), login.getUsername(), playerIp); } catch (GeneralSecurityException e) {
inbound.disconnect(Component.translatable("multiplayer.disconnect.authservers_down")); logger.error("Unable to enable encryption for connection", e);
} // At this point, the connection is encrypted, but something's wrong on our side and
} catch (ExecutionException e) { // we can't do anything about it.
logger.error("Unable to authenticate with Mojang", e); mcConnection.close(true);
inbound.disconnect(Component.translatable("multiplayer.disconnect.authservers_down")); return;
} catch (InterruptedException e) { }
// not much we can do usefully
Thread.currentThread().interrupt(); if (response.statusCode() == 200) {
} final GameProfile profile = GENERAL_GSON.fromJson(response.body(),
}, mcConnection.eventLoop()); GameProfile.class);
// Not so fast, now we verify the public key for 1.19.1+
if (inbound.getIdentifiedKey() != null
&& inbound.getIdentifiedKey().getKeyRevision() == IdentifiedKey.Revision.LINKED_V2
&& inbound.getIdentifiedKey() instanceof IdentifiedKeyImpl) {
IdentifiedKeyImpl key = (IdentifiedKeyImpl) inbound.getIdentifiedKey();
if (!key.internalAddHolder(profile.getId())) {
inbound.disconnect(
Component.translatable("multiplayer.disconnect.invalid_public_key"));
}
}
// All went well, initialize the session.
mcConnection.setActiveSessionHandler(StateRegistry.LOGIN,
new AuthSessionHandler(server, inbound, profile, true));
} else if (response.statusCode() == 204) {
// Apparently an offline-mode user logged onto this online-mode proxy.
inbound.disconnect(
Component.translatable("velocity.error.online-mode-only", NamedTextColor.RED));
} else {
// Something else went wrong
logger.error(
"Got an unexpected error code {} whilst contacting Mojang to log in {} ({})",
response.statusCode(), login.getUsername(), playerIp);
inbound.disconnect(Component.translatable("multiplayer.disconnect.authservers_down"));
}
}, mcConnection.eventLoop());
} catch (GeneralSecurityException e) { } catch (GeneralSecurityException e) {
logger.error("Unable to enable encryption", e); logger.error("Unable to enable encryption", e);
mcConnection.close(true); mcConnection.close(true);

Datei anzeigen

@ -17,9 +17,6 @@
package com.velocitypowered.proxy.network; package com.velocitypowered.proxy.network;
import static org.asynchttpclient.Dsl.asyncHttpClient;
import static org.asynchttpclient.Dsl.config;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.velocitypowered.api.event.proxy.ListenerBoundEvent; import com.velocitypowered.api.event.proxy.ListenerBoundEvent;
import com.velocitypowered.api.event.proxy.ListenerCloseEvent; import com.velocitypowered.api.event.proxy.ListenerCloseEvent;
@ -37,15 +34,11 @@ import io.netty.channel.EventLoopGroup;
import io.netty.channel.WriteBufferWaterMark; import io.netty.channel.WriteBufferWaterMark;
import io.netty.util.concurrent.GlobalEventExecutor; import io.netty.util.concurrent.GlobalEventExecutor;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.http.HttpClient;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.asynchttpclient.AsyncHttpClient;
import org.asynchttpclient.RequestBuilder;
import org.asynchttpclient.filter.FilterContext;
import org.asynchttpclient.filter.FilterContext.FilterContextBuilder;
import org.asynchttpclient.filter.RequestFilter;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
@ -69,7 +62,7 @@ public final class ConnectionManager {
public final BackendChannelInitializerHolder backendChannelInitializer; public final BackendChannelInitializerHolder backendChannelInitializer;
private final SeparatePoolInetNameResolver resolver; private final SeparatePoolInetNameResolver resolver;
private final AsyncHttpClient httpClient; private final HttpClient httpClient;
/** /**
* Initalizes the {@code ConnectionManager}. * Initalizes the {@code ConnectionManager}.
@ -86,20 +79,9 @@ public final class ConnectionManager {
this.backendChannelInitializer = new BackendChannelInitializerHolder( this.backendChannelInitializer = new BackendChannelInitializerHolder(
new BackendChannelInitializer(this.server)); new BackendChannelInitializer(this.server));
this.resolver = new SeparatePoolInetNameResolver(GlobalEventExecutor.INSTANCE); this.resolver = new SeparatePoolInetNameResolver(GlobalEventExecutor.INSTANCE);
this.httpClient = asyncHttpClient(config() this.httpClient = HttpClient.newBuilder()
.setEventLoopGroup(this.workerGroup) .executor(this.workerGroup)
.setUserAgent(server.getVersion().getName() + "/" + server.getVersion().getVersion()) .build();
.addRequestFilter(new RequestFilter() {
@Override
public <T> FilterContext<T> filter(FilterContext<T> ctx) {
return new FilterContextBuilder<>(ctx)
.request(new RequestBuilder(ctx.getRequest())
.setNameResolver(resolver)
.build())
.build();
}
})
.build());
} }
public void logChannelInformation() { public void logChannelInformation() {
@ -256,8 +238,8 @@ public final class ConnectionManager {
return this.serverChannelInitializer; return this.serverChannelInitializer;
} }
public AsyncHttpClient getHttpClient() { public HttpClient getHttpClient() {
return httpClient; return this.httpClient;
} }
public BackendChannelInitializerHolder getBackendChannelInitializer() { public BackendChannelInitializerHolder getBackendChannelInitializer() {