Initial commit of adventure-adapted Velocity API.
This commit is contained in:
@@ -224,7 +224,7 @@ public class Metrics {
|
||||
)
|
||||
)
|
||||
) {
|
||||
VelocityServer.GSON.toJson(object, writer);
|
||||
VelocityServer.GENERAL_GSON.toJson(object, writer);
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@ import com.google.gson.GsonBuilder;
|
||||
import com.velocitypowered.api.event.EventManager;
|
||||
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||
import com.velocitypowered.api.event.proxy.ProxyReloadEvent;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.plugin.PluginContainer;
|
||||
import com.velocitypowered.api.plugin.PluginManager;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
@@ -68,10 +69,10 @@ import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.stream.Collectors;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.TranslatableComponent;
|
||||
import net.kyori.text.serializer.gson.GsonComponentSerializer;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.asynchttpclient.AsyncHttpClient;
|
||||
@@ -83,10 +84,18 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
public class VelocityServer implements ProxyServer {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger(VelocityServer.class);
|
||||
public static final Gson GSON = GsonComponentSerializer.populate(new GsonBuilder())
|
||||
public static final Gson GENERAL_GSON = new GsonBuilder()
|
||||
.registerTypeHierarchyAdapter(Favicon.class, new FaviconSerializer())
|
||||
.registerTypeHierarchyAdapter(GameProfile.class, new GameProfileSerializer())
|
||||
.create();
|
||||
private static final Gson PRE_1_16_COMPONENT_SERIALIZER =
|
||||
wrapAndAddTextSerializers(GsonComponentSerializer.colorDownsamplingGson())
|
||||
.registerTypeHierarchyAdapter(Favicon.class, new FaviconSerializer())
|
||||
.create();
|
||||
private static final Gson POST_1_16_COMPONENT_SERIALIZER =
|
||||
wrapAndAddTextSerializers(GsonComponentSerializer.gson())
|
||||
.registerTypeHierarchyAdapter(Favicon.class, new FaviconSerializer())
|
||||
.create();
|
||||
|
||||
private final ConnectionManager cm;
|
||||
private final ProxyOptions options;
|
||||
@@ -594,4 +603,22 @@ public class VelocityServer implements ProxyServer {
|
||||
}
|
||||
return configuration.getBind();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(net.kyori.adventure.text.@NonNull Component message) {
|
||||
Preconditions.checkNotNull(message, "message");
|
||||
for (ConnectedPlayer player : connectionsByUuid.values()) {
|
||||
player.sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static Gson getGsonInstance(ProtocolVersion version) {
|
||||
return version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0 ? POST_1_16_COMPONENT_SERIALIZER
|
||||
: PRE_1_16_COMPONENT_SERIALIZER;
|
||||
}
|
||||
|
||||
private static GsonBuilder wrapAndAddTextSerializers(GsonComponentSerializer serializer) {
|
||||
return net.kyori.text.serializer.gson.GsonComponentSerializer
|
||||
.populate(serializer.serializer().newBuilder());
|
||||
}
|
||||
}
|
||||
|
@@ -1,19 +1,16 @@
|
||||
package com.velocitypowered.proxy.config;
|
||||
|
||||
import com.electronwill.nightconfig.core.CommentedConfig;
|
||||
import com.electronwill.nightconfig.core.Config;
|
||||
import com.electronwill.nightconfig.core.UnmodifiableConfig;
|
||||
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.moandjiezana.toml.Toml;
|
||||
import com.velocitypowered.api.proxy.config.ProxyConfig;
|
||||
import com.velocitypowered.api.util.AdventureCompat;
|
||||
import com.velocitypowered.api.util.Favicon;
|
||||
import com.velocitypowered.proxy.Velocity;
|
||||
import com.velocitypowered.proxy.util.AddressUtil;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
@@ -22,14 +19,12 @@ import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
@@ -54,7 +49,7 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
private final Advanced advanced;
|
||||
private final Query query;
|
||||
private final Metrics metrics;
|
||||
private @MonotonicNonNull Component motdAsComponent;
|
||||
private net.kyori.adventure.text.@MonotonicNonNull Component motdAsComponent;
|
||||
private @Nullable Favicon favicon;
|
||||
|
||||
private VelocityConfiguration(Servers servers, ForcedHosts forcedHosts, Advanced advanced,
|
||||
@@ -161,7 +156,7 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
}
|
||||
|
||||
try {
|
||||
getMotdComponent();
|
||||
getMotd();
|
||||
} catch (Exception e) {
|
||||
logger.error("Can't parse your MOTD", e);
|
||||
valid = false;
|
||||
@@ -228,22 +223,23 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
return query.shouldQueryShowPlugins();
|
||||
}
|
||||
|
||||
public String getMotd() {
|
||||
return motd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the proxy's MOTD.
|
||||
*
|
||||
* @return the MOTD
|
||||
*/
|
||||
@Override
|
||||
public Component getMotdComponent() {
|
||||
public net.kyori.text.Component getMotdComponent() {
|
||||
return AdventureCompat.asOriginalTextComponent(this.getMotd());
|
||||
}
|
||||
|
||||
@Override
|
||||
public net.kyori.adventure.text.Component getMotd() {
|
||||
if (motdAsComponent == null) {
|
||||
if (motd.startsWith("{")) {
|
||||
motdAsComponent = GsonComponentSerializer.INSTANCE.deserialize(motd);
|
||||
motdAsComponent = GsonComponentSerializer.gson().deserialize(motd);
|
||||
} else {
|
||||
motdAsComponent = LegacyComponentSerializer.legacy().deserialize(motd, '&');
|
||||
motdAsComponent = LegacyComponentSerializer.legacy('&').deserialize(motd);
|
||||
}
|
||||
}
|
||||
return motdAsComponent;
|
||||
|
@@ -9,6 +9,7 @@ import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
import com.velocitypowered.api.event.command.PlayerAvailableCommandsEvent;
|
||||
import com.velocitypowered.api.event.connection.PluginMessageEvent;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
|
||||
import com.velocitypowered.proxy.VelocityServer;
|
||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
||||
@@ -216,7 +217,8 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
serverConn.getServer().removePlayer(serverConn.getPlayer());
|
||||
if (!serverConn.isGracefulDisconnect() && !exceptionTriggered) {
|
||||
serverConn.getPlayer().handleConnectionException(serverConn.getServer(),
|
||||
Disconnect.create(ConnectionMessages.UNEXPECTED_DISCONNECT), true);
|
||||
Disconnect.create(ConnectionMessages.UNEXPECTED_DISCONNECT,
|
||||
ProtocolVersion.MINECRAFT_1_16), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -26,7 +26,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
|
||||
public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
package com.velocitypowered.proxy.connection.backend;
|
||||
|
||||
import static com.velocitypowered.proxy.VelocityServer.GSON;
|
||||
import static com.velocitypowered.proxy.VelocityServer.GENERAL_GSON;
|
||||
import static com.velocitypowered.proxy.connection.forge.legacy.LegacyForgeConstants.HANDSHAKE_HOSTNAME_TOKEN;
|
||||
import static com.velocitypowered.proxy.network.Connections.HANDLER;
|
||||
|
||||
@@ -105,7 +105,8 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
|
||||
.append('\0')
|
||||
.append(proxyPlayer.getGameProfile().getUndashedId())
|
||||
.append('\0');
|
||||
GSON.toJson(propertiesTransform.apply(proxyPlayer.getGameProfile().getProperties()), data);
|
||||
GENERAL_GSON
|
||||
.toJson(propertiesTransform.apply(proxyPlayer.getGameProfile().getProperties()), data);
|
||||
return data.toString();
|
||||
}
|
||||
|
||||
|
@@ -4,6 +4,8 @@ import static com.velocitypowered.proxy.connection.util.ConnectionRequestResults
|
||||
import static java.util.concurrent.CompletableFuture.completedFuture;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Verify;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.velocitypowered.api.event.connection.DisconnectEvent;
|
||||
import com.velocitypowered.api.event.player.KickedFromServerEvent;
|
||||
@@ -61,18 +63,19 @@ import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.TranslatableComponent;
|
||||
import net.kyori.text.format.TextColor;
|
||||
import net.kyori.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.text.serializer.plain.PlainComponentSerializer;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer;
|
||||
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.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
@@ -218,7 +221,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(Component component, MessagePosition position) {
|
||||
public void sendMessage(net.kyori.text.Component component, MessagePosition position) {
|
||||
Preconditions.checkNotNull(component, "component");
|
||||
Preconditions.checkNotNull(position, "position");
|
||||
|
||||
@@ -229,18 +232,20 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
// We can use the title packet instead.
|
||||
TitlePacket pkt = new TitlePacket();
|
||||
pkt.setAction(TitlePacket.SET_ACTION_BAR);
|
||||
pkt.setComponent(GsonComponentSerializer.INSTANCE.serialize(component));
|
||||
pkt.setComponent(net.kyori.text.serializer.gson.GsonComponentSerializer.INSTANCE
|
||||
.serialize(component));
|
||||
connection.write(pkt);
|
||||
return;
|
||||
} else {
|
||||
// Due to issues with action bar packets, we'll need to convert the text message into a
|
||||
// legacy message and then inject the legacy text into a component... yuck!
|
||||
JsonObject object = new JsonObject();
|
||||
object.addProperty("text", LegacyComponentSerializer.legacy().serialize(component));
|
||||
object.addProperty("text", net.kyori.text.serializer.legacy
|
||||
.LegacyComponentSerializer.legacy().serialize(component));
|
||||
json = object.toString();
|
||||
}
|
||||
} else {
|
||||
json = GsonComponentSerializer.INSTANCE.serialize(component);
|
||||
json = net.kyori.text.serializer.gson.GsonComponentSerializer.INSTANCE.serialize(component);
|
||||
}
|
||||
|
||||
Chat chat = new Chat();
|
||||
@@ -249,6 +254,31 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
connection.write(chat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(net.kyori.adventure.text.@NonNull Component message) {
|
||||
connection.write(Chat.createClientbound(message, this.getProtocolVersion()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendActionBar(net.kyori.adventure.text.@NonNull Component message) {
|
||||
if (getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_11) >= 0) {
|
||||
// We can use the title packet instead.
|
||||
TitlePacket pkt = new TitlePacket();
|
||||
pkt.setAction(TitlePacket.SET_ACTION_BAR);
|
||||
pkt.setComponent(VelocityServer.getGsonInstance(this.getProtocolVersion()).toJson(message));
|
||||
connection.write(pkt);
|
||||
} else {
|
||||
// Due to issues with action bar packets, we'll need to convert the text message into a
|
||||
// legacy message and then inject the legacy text into a component... yuck!
|
||||
JsonObject object = new JsonObject();
|
||||
object.addProperty("text", LegacyComponentSerializer.legacy().serialize(message));
|
||||
Chat chat = new Chat();
|
||||
chat.setMessage(object.toString());
|
||||
chat.setType((byte) 1);
|
||||
connection.write(chat);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionRequestBuilder createConnectionRequest(RegisteredServer server) {
|
||||
return new ConnectionRequestBuilderImpl(server);
|
||||
@@ -265,7 +295,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeaderAndFooter(Component header, Component footer) {
|
||||
public void setHeaderAndFooter(net.kyori.text.Component header, net.kyori.text.Component footer) {
|
||||
tabList.setHeaderAndFooter(header, footer);
|
||||
}
|
||||
|
||||
@@ -288,6 +318,26 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(net.kyori.text.Component reason) {
|
||||
if (connection.eventLoop().inEventLoop()) {
|
||||
disconnect0(reason, false);
|
||||
} else {
|
||||
connection.eventLoop().execute(() -> disconnect0(reason, false));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects the player from the proxy.
|
||||
* @param reason the reason for disconnecting the player
|
||||
* @param duringLogin whether the disconnect happened during login
|
||||
*/
|
||||
public void disconnect0(net.kyori.text.Component reason, boolean duringLogin) {
|
||||
logger.info("{} has disconnected: {}", this,
|
||||
net.kyori.text.serializer.legacy.LegacyComponentSerializer.legacy().serialize(reason));
|
||||
connection.closeWith(Disconnect.create(reason));
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects the player from the proxy.
|
||||
* @param reason the reason for disconnecting the player
|
||||
@@ -296,7 +346,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
public void disconnect0(Component reason, boolean duringLogin) {
|
||||
logger.info("{} has disconnected: {}", this,
|
||||
LegacyComponentSerializer.legacy().serialize(reason));
|
||||
connection.closeWith(Disconnect.create(reason));
|
||||
connection.closeWith(Disconnect.create(reason, this.getProtocolVersion()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -310,24 +360,25 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
connection.write(TitlePacket.hideForProtocolVersion(protocolVersion));
|
||||
} else if (title instanceof TextTitle) {
|
||||
TextTitle tt = (TextTitle) title;
|
||||
Gson gson = VelocityServer.getGsonInstance(this.getProtocolVersion());
|
||||
|
||||
if (tt.isResetBeforeSend()) {
|
||||
connection.delayedWrite(TitlePacket.resetForProtocolVersion(protocolVersion));
|
||||
}
|
||||
|
||||
Optional<Component> titleText = tt.getTitle();
|
||||
Optional<net.kyori.text.Component> titleText = tt.getTitle();
|
||||
if (titleText.isPresent()) {
|
||||
TitlePacket titlePkt = new TitlePacket();
|
||||
titlePkt.setAction(TitlePacket.SET_TITLE);
|
||||
titlePkt.setComponent(GsonComponentSerializer.INSTANCE.serialize(titleText.get()));
|
||||
titlePkt.setComponent(gson.toJson(titleText.get()));
|
||||
connection.delayedWrite(titlePkt);
|
||||
}
|
||||
|
||||
Optional<Component> subtitleText = tt.getSubtitle();
|
||||
Optional<net.kyori.text.Component> subtitleText = tt.getSubtitle();
|
||||
if (subtitleText.isPresent()) {
|
||||
TitlePacket titlePkt = new TitlePacket();
|
||||
titlePkt.setAction(TitlePacket.SET_SUBTITLE);
|
||||
titlePkt.setComponent(GsonComponentSerializer.INSTANCE.serialize(subtitleText.get()));
|
||||
titlePkt.setComponent(gson.toJson(subtitleText.get()));
|
||||
connection.delayedWrite(titlePkt);
|
||||
}
|
||||
|
||||
@@ -391,7 +442,8 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
userMessage = "Unable to connect to " + server.getServerInfo().getName() + ". Try again "
|
||||
+ "later.";
|
||||
}
|
||||
handleConnectionException(server, null, TextComponent.of(userMessage, TextColor.RED), safe);
|
||||
handleConnectionException(server, null, TextComponent.of(userMessage,
|
||||
NamedTextColor.RED), safe);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -407,15 +459,14 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
return;
|
||||
}
|
||||
|
||||
Component disconnectReason = GsonComponentSerializer.INSTANCE.deserialize(
|
||||
disconnect.getReason());
|
||||
Component disconnectReason = GsonComponentSerializer.gson().deserialize(disconnect.getReason());
|
||||
String plainTextReason = PASS_THRU_TRANSLATE.serialize(disconnectReason);
|
||||
if (connectedServer != null && connectedServer.getServerInfo().equals(server.getServerInfo())) {
|
||||
logger.error("{}: kicked from server {}: {}", this, server.getServerInfo().getName(),
|
||||
plainTextReason);
|
||||
handleConnectionException(server, disconnectReason, TextComponent.builder()
|
||||
.content("Kicked from " + server.getServerInfo().getName() + ": ")
|
||||
.color(TextColor.RED)
|
||||
.color(NamedTextColor.RED)
|
||||
.append(disconnectReason)
|
||||
.build(), safe);
|
||||
} else {
|
||||
@@ -423,7 +474,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
server.getServerInfo().getName(), plainTextReason);
|
||||
handleConnectionException(server, disconnectReason, TextComponent.builder()
|
||||
.content("Can't connect to server " + server.getServerInfo().getName() + ": ")
|
||||
.color(TextColor.RED)
|
||||
.color(NamedTextColor.RED)
|
||||
.append(disconnectReason)
|
||||
.build(), safe);
|
||||
}
|
||||
@@ -448,7 +499,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
ServerKickResult result;
|
||||
if (kickedFromCurrent) {
|
||||
Optional<RegisteredServer> next = getNextServerToTry(rs);
|
||||
result = next.<ServerKickResult>map(RedirectPlayer::create)
|
||||
result = next.map(RedirectPlayer::create)
|
||||
.orElseGet(() -> DisconnectPlayer.create(friendlyReason));
|
||||
} else {
|
||||
// If we were kicked by going to another server, the connection should not be in flight
|
||||
@@ -479,10 +530,10 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
if (newResult == null || !newResult) {
|
||||
disconnect(friendlyReason);
|
||||
} else {
|
||||
if (res.getMessage() == null) {
|
||||
if (res.getMessageComponent() == null) {
|
||||
sendMessage(VelocityMessages.MOVED_TO_NEW_SERVER.append(friendlyReason));
|
||||
} else {
|
||||
sendMessage(res.getMessage());
|
||||
sendMessage(res.getMessageComponent());
|
||||
}
|
||||
}
|
||||
}, connection.eventLoop());
|
||||
@@ -816,8 +867,10 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
// Ignored; the plugin probably already handled this.
|
||||
break;
|
||||
case SERVER_DISCONNECTED:
|
||||
handleConnectionException(toConnect, Disconnect.create(status.getReason()
|
||||
.orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR)), status.isSafe());
|
||||
Component reason = status.getReasonComponent()
|
||||
.orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR);
|
||||
handleConnectionException(toConnect, Disconnect.create(reason,
|
||||
getProtocolVersion()), status.isSafe());
|
||||
break;
|
||||
default:
|
||||
// The only remaining value is successful (no need to do anything!)
|
||||
|
@@ -23,9 +23,10 @@ import io.netty.buffer.ByteBuf;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Optional;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.TranslatableComponent;
|
||||
import net.kyori.text.format.TextColor;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
@@ -55,7 +56,7 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
|
||||
@Override
|
||||
public boolean handle(LegacyHandshake packet) {
|
||||
connection.closeWith(LegacyDisconnect
|
||||
.from(TextComponent.of("Your client is old, please upgrade!", TextColor.RED)));
|
||||
.from(TextComponent.of("Your client is old, please upgrade!", NamedTextColor.RED)));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -101,15 +102,13 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
private void handleLogin(Handshake handshake, InitialInboundConnection ic) {
|
||||
if (!ProtocolVersion.isSupported(handshake.getProtocolVersion())) {
|
||||
connection.closeWith(Disconnect
|
||||
.create(TranslatableComponent.of("multiplayer.disconnect.outdated_client")));
|
||||
ic.disconnectQuietly(TranslatableComponent.of("multiplayer.disconnect.outdated_client"));
|
||||
return;
|
||||
}
|
||||
|
||||
InetAddress address = ((InetSocketAddress) connection.getRemoteAddress()).getAddress();
|
||||
if (!server.getIpAttemptLimiter().attempt(address)) {
|
||||
connection.closeWith(
|
||||
Disconnect.create(TextComponent.of("You are logging in too fast, try again later.")));
|
||||
ic.disconnectQuietly(TextComponent.of("You are logging in too fast, try again later."));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -119,8 +118,7 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
|
||||
// and lower, otherwise IP information will never get forwarded.
|
||||
if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN
|
||||
&& handshake.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_13) < 0) {
|
||||
connection.closeWith(Disconnect
|
||||
.create(TextComponent.of("This server is only compatible with 1.13 and above.")));
|
||||
ic.disconnectQuietly(TextComponent.of("This server is only compatible with 1.13 and above."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -8,8 +8,8 @@ import com.velocitypowered.proxy.protocol.packet.Disconnect;
|
||||
import com.velocitypowered.proxy.protocol.packet.Handshake;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Optional;
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -61,6 +61,14 @@ public final class InitialInboundConnection implements InboundConnection,
|
||||
public void disconnect(Component reason) {
|
||||
logger.info("{} has disconnected: {}", this,
|
||||
LegacyComponentSerializer.legacy().serialize(reason));
|
||||
connection.closeWith(Disconnect.create(reason));
|
||||
connection.closeWith(Disconnect.create(reason, getProtocolVersion()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects the connection from the server silently.
|
||||
* @param reason the reason for disconnecting
|
||||
*/
|
||||
public void disconnectQuietly(Component reason) {
|
||||
connection.closeWith(Disconnect.create(reason, getProtocolVersion()));
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@ package com.velocitypowered.proxy.connection.client;
|
||||
|
||||
import static com.google.common.net.UrlEscapers.urlFormParameterEscaper;
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_8;
|
||||
import static com.velocitypowered.proxy.VelocityServer.GSON;
|
||||
import static com.velocitypowered.proxy.VelocityServer.GENERAL_GSON;
|
||||
import static com.velocitypowered.proxy.connection.VelocityConstants.EMPTY_BYTE_ARRAY;
|
||||
import static com.velocitypowered.proxy.util.EncryptionUtils.decryptRsa;
|
||||
import static com.velocitypowered.proxy.util.EncryptionUtils.generateServerId;
|
||||
@@ -124,7 +124,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
Response profileResponse = hasJoinedResponse.get();
|
||||
if (profileResponse.getStatusCode() == 200) {
|
||||
// All went well, initialize the session.
|
||||
initializePlayer(GSON.fromJson(profileResponse.getResponseBody(), GameProfile.class),
|
||||
initializePlayer(GENERAL_GSON.fromJson(profileResponse.getResponseBody(), GameProfile.class),
|
||||
true);
|
||||
} else if (profileResponse.getStatusCode() == 204) {
|
||||
// Apparently an offline-mode user logged onto this online-mode proxy.
|
||||
|
@@ -1,12 +1,14 @@
|
||||
package com.velocitypowered.proxy.connection.client;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gson.Gson;
|
||||
import com.spotify.futures.CompletableFutures;
|
||||
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.proxy.InboundConnection;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import com.velocitypowered.api.proxy.server.ServerPing;
|
||||
import com.velocitypowered.api.util.Favicon;
|
||||
import com.velocitypowered.api.util.ModInfo;
|
||||
import com.velocitypowered.proxy.VelocityServer;
|
||||
import com.velocitypowered.proxy.config.PingPassthroughMode;
|
||||
@@ -18,6 +20,7 @@ import com.velocitypowered.proxy.protocol.packet.LegacyPing;
|
||||
import com.velocitypowered.proxy.protocol.packet.StatusPing;
|
||||
import com.velocitypowered.proxy.protocol.packet.StatusRequest;
|
||||
import com.velocitypowered.proxy.protocol.packet.StatusResponse;
|
||||
import com.velocitypowered.proxy.protocol.util.FaviconSerializer;
|
||||
import com.velocitypowered.proxy.server.VelocityRegisteredServer;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.net.InetSocketAddress;
|
||||
@@ -25,11 +28,23 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class StatusSessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
private static final Gson PRE_1_16_PING_SERIALIZER = GsonComponentSerializer
|
||||
.colorDownsamplingGson()
|
||||
.serializer()
|
||||
.newBuilder()
|
||||
.registerTypeHierarchyAdapter(Favicon.class, new FaviconSerializer())
|
||||
.create();
|
||||
private static final Gson POST_1_16_PING_SERIALIZER = GsonComponentSerializer.gson()
|
||||
.serializer()
|
||||
.newBuilder()
|
||||
.registerTypeHierarchyAdapter(Favicon.class, new FaviconSerializer())
|
||||
.create();
|
||||
private static final Logger logger = LogManager.getLogger(StatusSessionHandler.class);
|
||||
|
||||
private final VelocityServer server;
|
||||
@@ -58,7 +73,7 @@ public class StatusSessionHandler implements MinecraftSessionHandler {
|
||||
"Velocity " + ProtocolVersion.SUPPORTED_VERSION_STRING),
|
||||
new ServerPing.Players(server.getPlayerCount(), configuration.getShowMaxPlayers(),
|
||||
ImmutableList.of()),
|
||||
configuration.getMotdComponent(),
|
||||
configuration.getMotd(),
|
||||
configuration.getFavicon().orElse(null),
|
||||
configuration.isAnnounceForge() ? ModInfo.DEFAULT : null
|
||||
);
|
||||
@@ -119,7 +134,7 @@ public class StatusSessionHandler implements MinecraftSessionHandler {
|
||||
return new ServerPing(
|
||||
fallback.getVersion(),
|
||||
fallback.getPlayers().orElse(null),
|
||||
response.getDescription(),
|
||||
response.getDescriptionComponent(),
|
||||
fallback.getFavicon().orElse(null),
|
||||
response.getModinfo().orElse(null)
|
||||
);
|
||||
@@ -173,7 +188,8 @@ public class StatusSessionHandler implements MinecraftSessionHandler {
|
||||
.thenAcceptAsync(
|
||||
(event) -> {
|
||||
StringBuilder json = new StringBuilder();
|
||||
VelocityServer.GSON.toJson(event.getPing(), json);
|
||||
VelocityServer.getGsonInstance(connection.getProtocolVersion())
|
||||
.toJson(event.getPing(), json);
|
||||
connection.write(new StatusResponse(json));
|
||||
},
|
||||
connection.eventLoop());
|
||||
|
@@ -1,14 +1,14 @@
|
||||
package com.velocitypowered.proxy.connection.util;
|
||||
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.format.TextColor;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
public class ConnectionMessages {
|
||||
|
||||
public static final TextComponent ALREADY_CONNECTED = TextComponent
|
||||
.of("You are already connected to this server!", TextColor.RED);
|
||||
.of("You are already connected to this server!", NamedTextColor.RED);
|
||||
public static final TextComponent IN_PROGRESS = TextComponent
|
||||
.of("You are already connecting to a server!", TextColor.RED);
|
||||
.of("You are already connecting to a server!", NamedTextColor.RED);
|
||||
public static final TextComponent INTERNAL_SERVER_CONNECTION_ERROR = TextComponent
|
||||
.of("Internal server connection error");
|
||||
public static final TextComponent UNEXPECTED_DISCONNECT = TextComponent
|
||||
|
@@ -3,11 +3,12 @@ package com.velocitypowered.proxy.connection.util;
|
||||
import com.velocitypowered.api.proxy.ConnectionRequestBuilder;
|
||||
import com.velocitypowered.api.proxy.ConnectionRequestBuilder.Status;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import com.velocitypowered.api.util.AdventureCompat;
|
||||
import com.velocitypowered.proxy.protocol.packet.Disconnect;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
|
||||
public class ConnectionRequestResults {
|
||||
|
||||
@@ -42,19 +43,19 @@ public class ConnectionRequestResults {
|
||||
}
|
||||
|
||||
public static Impl forDisconnect(Disconnect disconnect, RegisteredServer server) {
|
||||
Component deserialized = GsonComponentSerializer.INSTANCE.deserialize(disconnect.getReason());
|
||||
Component deserialized = GsonComponentSerializer.gson().deserialize(disconnect.getReason());
|
||||
return forDisconnect(deserialized, server);
|
||||
}
|
||||
|
||||
public static Impl forUnsafeDisconnect(Disconnect disconnect, RegisteredServer server) {
|
||||
Component deserialized = GsonComponentSerializer.INSTANCE.deserialize(disconnect.getReason());
|
||||
Component deserialized = GsonComponentSerializer.gson().deserialize(disconnect.getReason());
|
||||
return new Impl(Status.SERVER_DISCONNECTED, deserialized, server, false);
|
||||
}
|
||||
|
||||
public static class Impl implements ConnectionRequestBuilder.Result {
|
||||
|
||||
private final Status status;
|
||||
private final @Nullable Component component;
|
||||
private final @Nullable net.kyori.adventure.text.Component component;
|
||||
private final RegisteredServer attemptedConnection;
|
||||
private final boolean safe;
|
||||
|
||||
@@ -72,7 +73,12 @@ public class ConnectionRequestResults {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Component> getReason() {
|
||||
public Optional<net.kyori.text.Component> getReason() {
|
||||
return Optional.ofNullable(component).map(AdventureCompat::asOriginalTextComponent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Component> getReasonComponent() {
|
||||
return Optional.ofNullable(component);
|
||||
}
|
||||
|
||||
|
@@ -8,10 +8,8 @@ import com.velocitypowered.api.permission.Tristate;
|
||||
import com.velocitypowered.api.proxy.ConsoleCommandSource;
|
||||
import com.velocitypowered.proxy.VelocityServer;
|
||||
import java.util.List;
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.format.TextColor;
|
||||
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.minecrell.terminalconsole.SimpleTerminalConsole;
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@@ -34,8 +32,15 @@ public final class VelocityConsole extends SimpleTerminalConsole implements Cons
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(Component component) {
|
||||
logger.info(LegacyComponentSerializer.legacy().serialize(component));
|
||||
public void sendMessage(net.kyori.text.Component component) {
|
||||
logger.info(net.kyori.text.serializer.legacy.LegacyComponentSerializer.legacy()
|
||||
.serialize(component));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(net.kyori.adventure.text.@NonNull Component message) {
|
||||
logger.info(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacy()
|
||||
.serialize(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -103,5 +108,4 @@ public final class VelocityConsole extends SimpleTerminalConsole implements Cons
|
||||
protected void shutdown() {
|
||||
this.server.shutdown(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -117,7 +117,7 @@ public class JavaPluginLoader implements PluginLoader {
|
||||
while ((entry = in.getNextJarEntry()) != null) {
|
||||
if (entry.getName().equals("velocity-plugin.json")) {
|
||||
try (Reader pluginInfoReader = new InputStreamReader(in, StandardCharsets.UTF_8)) {
|
||||
return Optional.of(VelocityServer.GSON
|
||||
return Optional.of(VelocityServer.GENERAL_GSON
|
||||
.fromJson(pluginInfoReader, SerializedPluginDescription.class));
|
||||
}
|
||||
}
|
||||
|
@@ -26,7 +26,7 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import net.kyori.text.serializer.plain.PlainComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
@@ -72,8 +72,7 @@ public class GS4QueryHandler extends SimpleChannelInboundHandler<DatagramPacket>
|
||||
|
||||
private QueryResponse createInitialResponse() {
|
||||
return QueryResponse.builder()
|
||||
.hostname(PlainComponentSerializer.INSTANCE
|
||||
.serialize(server.getConfiguration().getMotdComponent()))
|
||||
.hostname(PlainComponentSerializer.INSTANCE.serialize(server.getConfiguration().getMotd()))
|
||||
.gameVersion(ProtocolVersion.SUPPORTED_VERSION_STRING)
|
||||
.map(server.getConfiguration().getQueryMap())
|
||||
.currentPlayers(server.getPlayerCount())
|
||||
|
@@ -2,12 +2,11 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.VelocityServer;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.serializer.gson.GsonComponentSerializer;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.UUID;
|
||||
@@ -97,13 +96,27 @@ public class Chat implements MinecraftPacket {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static Chat createClientbound(Component component) {
|
||||
@Deprecated
|
||||
public static Chat createClientbound(net.kyori.text.Component component) {
|
||||
return createClientbound(component, CHAT_TYPE, EMPTY_SENDER);
|
||||
}
|
||||
|
||||
public static Chat createClientbound(Component component, byte type, UUID sender) {
|
||||
@Deprecated
|
||||
public static Chat createClientbound(net.kyori.text.Component component, byte type, UUID sender) {
|
||||
Preconditions.checkNotNull(component, "component");
|
||||
return new Chat(GsonComponentSerializer.INSTANCE.serialize(component), type, sender);
|
||||
return new Chat(net.kyori.text.serializer.gson.GsonComponentSerializer.INSTANCE
|
||||
.serialize(component), type, sender);
|
||||
}
|
||||
|
||||
public static Chat createClientbound(net.kyori.adventure.text.Component component,
|
||||
ProtocolVersion version) {
|
||||
return createClientbound(component, CHAT_TYPE, EMPTY_SENDER, version);
|
||||
}
|
||||
|
||||
public static Chat createClientbound(net.kyori.adventure.text.Component component, byte type,
|
||||
UUID sender, ProtocolVersion version) {
|
||||
Preconditions.checkNotNull(component, "component");
|
||||
return new Chat(VelocityServer.getGsonInstance(version).toJson(component), type, sender);
|
||||
}
|
||||
|
||||
public static Chat createServerbound(String message) {
|
||||
|
@@ -2,6 +2,7 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.VelocityServer;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
@@ -57,8 +58,15 @@ public class Disconnect implements MinecraftPacket {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Disconnect create(Component component) {
|
||||
Preconditions.checkNotNull(component, "component");
|
||||
return new Disconnect(GsonComponentSerializer.INSTANCE.serialize(component));
|
||||
}
|
||||
|
||||
public static Disconnect create(net.kyori.adventure.text.Component component,
|
||||
ProtocolVersion version) {
|
||||
Preconditions.checkNotNull(component, "component");
|
||||
return new Disconnect(VelocityServer.getGsonInstance(version).toJson(component));
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,9 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import static com.velocitypowered.proxy.protocol.ProtocolUtils.writeString;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.Gson;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.VelocityServer;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
@@ -58,6 +60,12 @@ public class HeaderAndFooter implements MinecraftPacket {
|
||||
return new HeaderAndFooter(json.serialize(header), json.serialize(footer));
|
||||
}
|
||||
|
||||
public static HeaderAndFooter create(net.kyori.adventure.text.Component header,
|
||||
net.kyori.adventure.text.Component footer, ProtocolVersion protocolVersion) {
|
||||
Gson serializer = VelocityServer.getGsonInstance(protocolVersion);
|
||||
return new HeaderAndFooter(serializer.toJson(header), serializer.toJson(footer));
|
||||
}
|
||||
|
||||
public static HeaderAndFooter reset() {
|
||||
return RESET;
|
||||
}
|
||||
|
@@ -4,9 +4,9 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.velocitypowered.api.proxy.server.ServerPing;
|
||||
import com.velocitypowered.api.proxy.server.ServerPing.Players;
|
||||
import com.velocitypowered.proxy.protocol.packet.legacyping.LegacyMinecraftPingVersion;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.text.serializer.plain.PlainComponentSerializer;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer;
|
||||
|
||||
public class LegacyDisconnect {
|
||||
|
||||
@@ -36,7 +36,8 @@ public class LegacyDisconnect {
|
||||
// remove all section symbols, along with fetching just the first line of an (unformatted)
|
||||
// MOTD.
|
||||
return new LegacyDisconnect(String.join(LEGACY_COLOR_CODE,
|
||||
cleanSectionSymbol(getFirstLine(PlainComponentSerializer.INSTANCE.serialize(response.getDescription()))),
|
||||
cleanSectionSymbol(getFirstLine(PlainComponentSerializer.INSTANCE.serialize(
|
||||
response.getDescriptionComponent()))),
|
||||
Integer.toString(players.getOnline()),
|
||||
Integer.toString(players.getMax())));
|
||||
case MINECRAFT_1_4:
|
||||
@@ -46,7 +47,8 @@ public class LegacyDisconnect {
|
||||
LEGACY_COLOR_CODE + "1",
|
||||
Integer.toString(response.getVersion().getProtocol()),
|
||||
response.getVersion().getName(),
|
||||
getFirstLine(LegacyComponentSerializer.legacy().serialize(response.getDescription())),
|
||||
getFirstLine(LegacyComponentSerializer.legacy().serialize(response
|
||||
.getDescriptionComponent())),
|
||||
Integer.toString(players.getOnline()),
|
||||
Integer.toString(players.getMax())
|
||||
));
|
||||
|
@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.proxy.player.TabListEntry;
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
import com.velocitypowered.proxy.VelocityServer;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
@@ -11,9 +12,9 @@ import io.netty.buffer.ByteBuf;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class PlayerListItem implements MinecraftPacket {
|
||||
@@ -86,7 +87,7 @@ public class PlayerListItem implements MinecraftPacket {
|
||||
|
||||
private static @Nullable Component readOptionalComponent(ByteBuf buf) {
|
||||
if (buf.readBoolean()) {
|
||||
return GsonComponentSerializer.INSTANCE.deserialize(ProtocolUtils.readString(buf));
|
||||
return GsonComponentSerializer.gson().deserialize(ProtocolUtils.readString(buf));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -105,7 +106,7 @@ public class PlayerListItem implements MinecraftPacket {
|
||||
ProtocolUtils.writeVarInt(buf, item.getGameMode());
|
||||
ProtocolUtils.writeVarInt(buf, item.getLatency());
|
||||
|
||||
writeDisplayName(buf, item.getDisplayName());
|
||||
writeDisplayName(buf, item.getDisplayName(), version);
|
||||
break;
|
||||
case UPDATE_GAMEMODE:
|
||||
ProtocolUtils.writeVarInt(buf, item.getGameMode());
|
||||
@@ -114,10 +115,10 @@ public class PlayerListItem implements MinecraftPacket {
|
||||
ProtocolUtils.writeVarInt(buf, item.getLatency());
|
||||
break;
|
||||
case UPDATE_DISPLAY_NAME:
|
||||
writeDisplayName(buf, item.getDisplayName());
|
||||
writeDisplayName(buf, item.getDisplayName(), version);
|
||||
break;
|
||||
case REMOVE_PLAYER:
|
||||
//Do nothing, all that is needed is the uuid
|
||||
// Do nothing, all that is needed is the uuid
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unknown action " + action);
|
||||
@@ -142,10 +143,11 @@ public class PlayerListItem implements MinecraftPacket {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
private void writeDisplayName(ByteBuf buf, @Nullable Component displayName) {
|
||||
private void writeDisplayName(ByteBuf buf, @Nullable Component displayName,
|
||||
ProtocolVersion version) {
|
||||
buf.writeBoolean(displayName != null);
|
||||
if (displayName != null) {
|
||||
ProtocolUtils.writeString(buf, GsonComponentSerializer.INSTANCE.serialize(displayName));
|
||||
ProtocolUtils.writeString(buf, VelocityServer.getGsonInstance(version).toJson(displayName));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +174,7 @@ public class PlayerListItem implements MinecraftPacket {
|
||||
.setProperties(entry.getProfile().getProperties())
|
||||
.setLatency(entry.getLatency())
|
||||
.setGameMode(entry.getGameMode())
|
||||
.setDisplayName(entry.getDisplayName().orElse(null));
|
||||
.setDisplayName(entry.getDisplayNameComponent().orElse(null));
|
||||
}
|
||||
|
||||
public @Nullable UUID getUuid() {
|
||||
|
@@ -50,7 +50,8 @@ public class PingSessionHandler implements MinecraftSessionHandler {
|
||||
completed = true;
|
||||
connection.close(true);
|
||||
|
||||
ServerPing ping = VelocityServer.GSON.fromJson(packet.getStatus(), ServerPing.class);
|
||||
ServerPing ping = VelocityServer.getGsonInstance(version).fromJson(packet.getStatus(),
|
||||
ServerPing.class);
|
||||
result.complete(ping);
|
||||
return true;
|
||||
}
|
||||
|
@@ -37,6 +37,8 @@ import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class VelocityRegisteredServer implements RegisteredServer {
|
||||
@@ -145,4 +147,11 @@ public class VelocityRegisteredServer implements RegisteredServer {
|
||||
public String toString() {
|
||||
return "registered server: " + serverInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(@NonNull Component message) {
|
||||
for (ConnectedPlayer player : players) {
|
||||
player.sendMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -34,6 +34,14 @@ public class VelocityTabList implements TabList {
|
||||
connection.write(HeaderAndFooter.create(header, footer));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeaderAndFooter(net.kyori.adventure.text.Component header,
|
||||
net.kyori.adventure.text.Component footer) {
|
||||
Preconditions.checkNotNull(header, "header");
|
||||
Preconditions.checkNotNull(footer, "footer");
|
||||
connection.write(HeaderAndFooter.create(header, footer, connection.getProtocolVersion()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearHeaderAndFooter() {
|
||||
connection.write(HeaderAndFooter.reset());
|
||||
@@ -97,8 +105,8 @@ public class VelocityTabList implements TabList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TabListEntry buildEntry(GameProfile profile, @Nullable Component displayName, int latency,
|
||||
int gameMode) {
|
||||
public TabListEntry buildEntry(GameProfile profile,
|
||||
net.kyori.adventure.text.@Nullable Component displayName, int latency, int gameMode) {
|
||||
return new VelocityTabListEntry(this, profile, displayName, latency, gameMode);
|
||||
}
|
||||
|
||||
|
@@ -2,6 +2,7 @@ package com.velocitypowered.proxy.tablist;
|
||||
|
||||
import com.velocitypowered.api.proxy.player.TabList;
|
||||
import com.velocitypowered.api.proxy.player.TabListEntry;
|
||||
import com.velocitypowered.api.util.AdventureCompat;
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
import com.velocitypowered.proxy.protocol.packet.PlayerListItem;
|
||||
import java.util.Optional;
|
||||
@@ -12,12 +13,12 @@ public class VelocityTabListEntry implements TabListEntry {
|
||||
|
||||
private final VelocityTabList tabList;
|
||||
private final GameProfile profile;
|
||||
private @Nullable Component displayName;
|
||||
private net.kyori.adventure.text.Component displayName;
|
||||
private int latency;
|
||||
private int gameMode;
|
||||
|
||||
VelocityTabListEntry(VelocityTabList tabList, GameProfile profile,
|
||||
@Nullable Component displayName, int latency, int gameMode) {
|
||||
net.kyori.adventure.text.@Nullable Component displayName, int latency, int gameMode) {
|
||||
this.tabList = tabList;
|
||||
this.profile = profile;
|
||||
this.displayName = displayName;
|
||||
@@ -37,17 +38,27 @@ public class VelocityTabListEntry implements TabListEntry {
|
||||
|
||||
@Override
|
||||
public Optional<Component> getDisplayName() {
|
||||
return Optional.ofNullable(displayName).map(AdventureCompat::asOriginalTextComponent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<net.kyori.adventure.text.Component> getDisplayNameComponent() {
|
||||
return Optional.ofNullable(displayName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TabListEntry setDisplayName(@Nullable Component displayName) {
|
||||
return this.setDisplayName(AdventureCompat.asAdventureComponent(displayName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TabListEntry setDisplayName(net.kyori.adventure.text.@Nullable Component displayName) {
|
||||
this.displayName = displayName;
|
||||
tabList.updateEntry(PlayerListItem.UPDATE_DISPLAY_NAME, this);
|
||||
return this;
|
||||
}
|
||||
|
||||
void setDisplayNameInternal(@Nullable Component displayName) {
|
||||
void setDisplayNameInternal(net.kyori.adventure.text.@Nullable Component displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,7 @@ package com.velocitypowered.proxy.tablist;
|
||||
|
||||
import com.velocitypowered.api.proxy.player.TabListEntry;
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class VelocityTabListEntryLegacy extends VelocityTabListEntry {
|
||||
|
@@ -11,7 +11,7 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class VelocityTabListLegacy extends VelocityTabList {
|
||||
@@ -22,6 +22,10 @@ public class VelocityTabListLegacy extends VelocityTabList {
|
||||
super(connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeaderAndFooter(net.kyori.text.Component header, net.kyori.text.Component footer) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeaderAndFooter(Component header, Component footer) {
|
||||
}
|
||||
@@ -55,7 +59,6 @@ public class VelocityTabListLegacy extends VelocityTabList {
|
||||
|
||||
@Override
|
||||
public void processBackendPacket(PlayerListItem packet) {
|
||||
|
||||
Item item = packet.getItems().get(0); // Only one item per packet in 1.7
|
||||
|
||||
switch (packet.getAction()) {
|
||||
|
@@ -1,27 +1,25 @@
|
||||
package com.velocitypowered.proxy.util;
|
||||
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.format.TextColor;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
public class VelocityMessages {
|
||||
|
||||
public static final Component ONLINE_MODE_ONLY = TextComponent
|
||||
.builder("This server only accepts connections from online-mode clients.")
|
||||
.color(TextColor.RED)
|
||||
.color(NamedTextColor.RED)
|
||||
.append(
|
||||
TextComponent.of("\n\nDid you change your username? Sign out of Minecraft, sign back in, "
|
||||
+ "and try again.", TextColor.GRAY)
|
||||
+ "and try again.", NamedTextColor.GRAY)
|
||||
)
|
||||
.build();
|
||||
public static final Component NO_PROXY_BEHIND_PROXY = TextComponent
|
||||
.of("Running Velocity behind Velocity isn't supported.", TextColor.RED);
|
||||
public static final Component NO_AVAILABLE_SERVERS = TextComponent
|
||||
.of("No available servers", TextColor.RED);
|
||||
.of("No available servers", NamedTextColor.RED);
|
||||
public static final Component ALREADY_CONNECTED = TextComponent
|
||||
.of("You are already connected to this proxy!", TextColor.RED);
|
||||
.of("You are already connected to this proxy!", NamedTextColor.RED);
|
||||
public static final Component MOVED_TO_NEW_SERVER = TextComponent
|
||||
.of("The server you were on kicked you: ", TextColor.RED);
|
||||
.of("The server you were on kicked you: ", NamedTextColor.RED);
|
||||
|
||||
private VelocityMessages() {
|
||||
throw new AssertionError();
|
||||
|
Reference in New Issue
Block a user