Compare commits
26 Commits
updatev2
...
b6e05cb0b9
| Author | SHA1 | Date | |
|---|---|---|---|
| b6e05cb0b9 | |||
| 1507b91463 | |||
| b06af3718c | |||
| a20a896582 | |||
| e1a3421212 | |||
| 19e51a2b12 | |||
| b89a5c5ce9 | |||
| 65d3277319 | |||
| a22bfa10f9 | |||
| d9d1319a3a | |||
| 15ecbf4345 | |||
| 5e3bbcd427 | |||
| a6c79db07b | |||
| 6e33bc6c17 | |||
| 01208bb359 | |||
| fa88aaae52 | |||
| 2da400a267 | |||
| 8103135dfb | |||
| cfabff7288 | |||
| 2f5a27a708 | |||
| fdfe8bcc4b | |||
| a19fd8db74 | |||
| e63d71423d | |||
| a7afe35fab | |||
| 56d6339313 | |||
| 2475572573 |
@ -7,10 +7,8 @@
|
||||
|
||||
package com.velocitypowered.api.command;
|
||||
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.velocitypowered.api.event.command.CommandExecuteEvent;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Predicate;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
@ -118,27 +116,6 @@ public interface CommandManager {
|
||||
*/
|
||||
CompletableFuture<Boolean> executeImmediatelyAsync(CommandSource source, String cmdLine);
|
||||
|
||||
/**
|
||||
* Asynchronously collects suggestions to fill in the given command {@code cmdLine}.
|
||||
* Returns only the raw completion suggestions without tooltips.
|
||||
*
|
||||
* @param source the source to execute the command for
|
||||
* @param cmdLine the partially completed command
|
||||
* @return a {@link CompletableFuture} eventually completed with a {@link List}, possibly empty
|
||||
*/
|
||||
CompletableFuture<List<String>> offerSuggestions(CommandSource source, String cmdLine);
|
||||
|
||||
/**
|
||||
* Asynchronously collects suggestions to fill in the given command {@code cmdLine}.
|
||||
* Returns the brigadier {@link Suggestions} with tooltips for each result.
|
||||
*
|
||||
* @param source the source to execute the command for
|
||||
* @param cmdLine the partially completed command
|
||||
* @return a {@link CompletableFuture} eventually completed with {@link Suggestions}, possibly
|
||||
* empty
|
||||
*/
|
||||
CompletableFuture<Suggestions> offerBrigadierSuggestions(CommandSource source, String cmdLine);
|
||||
|
||||
/**
|
||||
* Returns an immutable collection of the case-insensitive aliases registered
|
||||
* on this manager.
|
||||
|
||||
@ -90,8 +90,7 @@ public enum ProtocolVersion implements Ordered<ProtocolVersion> {
|
||||
MINECRAFT_1_21(767, "1.21", "1.21.1"),
|
||||
MINECRAFT_1_21_2(768, "1.21.2", "1.21.3"),
|
||||
MINECRAFT_1_21_4(769, "1.21.4"),
|
||||
MINECRAFT_1_21_5(770, "1.21.5"),
|
||||
MINECRAFT_1_21_6(771, "1.21.6");
|
||||
MINECRAFT_1_21_5(770, /*1073742067,*/ "1.21.5");
|
||||
|
||||
private static final int SNAPSHOT_BIT = 30;
|
||||
|
||||
|
||||
@ -31,6 +31,7 @@ public final class ServerPing {
|
||||
private final net.kyori.adventure.text.Component description;
|
||||
private final @Nullable Favicon favicon;
|
||||
private final @Nullable ModInfo modinfo;
|
||||
private final boolean preventsChatReports = true;
|
||||
|
||||
public ServerPing(Version version, @Nullable Players players,
|
||||
net.kyori.adventure.text.Component description, @Nullable Favicon favicon) {
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
configurate3 = "3.7.3"
|
||||
configurate4 = "4.1.2"
|
||||
flare = "2.0.1"
|
||||
log4j = "2.24.3"
|
||||
netty = "4.2.1.Final"
|
||||
log4j = "2.24.1"
|
||||
netty = "4.2.0.Final"
|
||||
|
||||
[plugins]
|
||||
indra-publishing = "net.kyori.indra.publishing:2.0.6"
|
||||
@ -11,10 +11,10 @@ shadow = "io.github.goooler.shadow:8.1.5"
|
||||
spotless = "com.diffplug.spotless:6.25.0"
|
||||
|
||||
[libraries]
|
||||
adventure-bom = "net.kyori:adventure-bom:4.21.0"
|
||||
adventure-text-serializer-json-legacy-impl = "net.kyori:adventure-text-serializer-json-legacy-impl:4.21.0"
|
||||
adventure-bom = "net.kyori:adventure-bom:4.19.0"
|
||||
adventure-text-serializer-json-legacy-impl = "net.kyori:adventure-text-serializer-json-legacy-impl:4.19.0"
|
||||
adventure-facet = "net.kyori:adventure-platform-facet:4.3.4"
|
||||
asm = "org.ow2.asm:asm:9.8"
|
||||
asm = "org.ow2.asm:asm:9.7.1"
|
||||
auto-service = "com.google.auto.service:auto-service:1.0.1"
|
||||
auto-service-annotations = "com.google.auto.service:auto-service-annotations:1.0.1"
|
||||
brigadier = "com.velocitypowered:velocity-brigadier:1.0.0-SNAPSHOT"
|
||||
@ -33,7 +33,7 @@ disruptor = "com.lmax:disruptor:4.0.0"
|
||||
fastutil = "it.unimi.dsi:fastutil:8.5.15"
|
||||
flare-core = { module = "space.vectrix.flare:flare", version.ref = "flare" }
|
||||
flare-fastutil = { module = "space.vectrix.flare:flare-fastutil", version.ref = "flare" }
|
||||
jline = "org.jline:jline-terminal-jansi:3.30.2"
|
||||
jline = "org.jline:jline-terminal-jansi:3.27.1"
|
||||
jopt = "net.sf.jopt-simple:jopt-simple:5.0.4"
|
||||
junit = "org.junit.jupiter:junit-jupiter:5.10.2"
|
||||
jspecify = "org.jspecify:jspecify:0.3.0"
|
||||
@ -56,7 +56,7 @@ netty-transport-native-epoll = { module = "io.netty:netty-transport-native-epoll
|
||||
netty-transport-native-kqueue = { module = "io.netty:netty-transport-native-kqueue", version.ref = "netty" }
|
||||
netty-transport-native-iouring = { module = "io.netty:netty-transport-native-io_uring", version.ref = "netty" }
|
||||
nightconfig = "com.electronwill.night-config:toml:3.6.7"
|
||||
slf4j = "org.slf4j:slf4j-api:2.0.17"
|
||||
slf4j = "org.slf4j:slf4j-api:2.0.12"
|
||||
snakeyaml = "org.yaml:snakeyaml:1.33"
|
||||
spotbugs-annotations = "com.github.spotbugs:spotbugs-annotations:4.7.3"
|
||||
terminalconsoleappender = "net.minecrell:terminalconsoleappender:1.3.0"
|
||||
|
||||
@ -100,7 +100,6 @@ tasks {
|
||||
runShadow {
|
||||
workingDir = file("run").also(File::mkdirs)
|
||||
standardInput = System.`in`
|
||||
jvmArgs("-Dvelocity.packet-decode-logging=true")
|
||||
}
|
||||
named<JavaExec>("run") {
|
||||
workingDir = file("run").also(File::mkdirs)
|
||||
|
||||
@ -47,11 +47,6 @@ public class Velocity {
|
||||
System.setProperty("io.netty.native.workdir", System.getProperty("velocity.natives-tmpdir"));
|
||||
}
|
||||
|
||||
// Restore allocator used before Netty 4.2 due to oom issues with the adaptive allocator
|
||||
if (System.getProperty("io.netty.allocator.type") == null) {
|
||||
System.setProperty("io.netty.allocator.type", "pooled");
|
||||
}
|
||||
|
||||
// Disable the resource leak detector by default as it reduces performance. Allow the user to
|
||||
// override this if desired.
|
||||
if (!VelocityProperties.hasProperty("io.netty.leakDetection.level")) {
|
||||
|
||||
@ -81,7 +81,6 @@ import java.net.http.HttpClient;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyPair;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@ -105,7 +104,7 @@ import net.kyori.adventure.audience.ForwardingAudience;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.translation.GlobalTranslator;
|
||||
import net.kyori.adventure.translation.TranslationStore;
|
||||
import net.kyori.adventure.translation.TranslationRegistry;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bstats.MetricsBase;
|
||||
@ -338,8 +337,8 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
||||
}
|
||||
|
||||
private void registerTranslations() {
|
||||
final TranslationStore.StringBased<MessageFormat> translationRegistry =
|
||||
TranslationStore.messageFormat(Key.key("velocity", "translations"));
|
||||
final TranslationRegistry translationRegistry = TranslationRegistry
|
||||
.create(Key.key("velocity", "translations"));
|
||||
translationRegistry.defaultLocale(Locale.US);
|
||||
try {
|
||||
ResourceUtils.visitResources(VelocityServer.class, path -> {
|
||||
|
||||
@ -300,14 +300,27 @@ public class VelocityCommandManager implements CommandManager {
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Returns suggestions to fill in the given command.
|
||||
*
|
||||
* @param source the source to execute the command for
|
||||
* @param cmdLine the partially completed command
|
||||
* @return a {@link CompletableFuture} eventually completed with a {@link List}, possibly empty
|
||||
*/
|
||||
public CompletableFuture<List<String>> offerSuggestions(final CommandSource source,
|
||||
final String cmdLine) {
|
||||
return offerBrigadierSuggestions(source, cmdLine)
|
||||
.thenApply(suggestions -> Lists.transform(suggestions.getList(), Suggestion::getText));
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Returns suggestions to fill in the given command.
|
||||
*
|
||||
* @param source the source to execute the command for
|
||||
* @param cmdLine the partially completed command
|
||||
* @return a {@link CompletableFuture} eventually completed with {@link Suggestions}, possibly
|
||||
* empty
|
||||
*/
|
||||
public CompletableFuture<Suggestions> offerBrigadierSuggestions(
|
||||
final CommandSource source, final String cmdLine) {
|
||||
Preconditions.checkNotNull(source, "source");
|
||||
|
||||
@ -46,7 +46,6 @@ import com.velocitypowered.proxy.protocol.netty.MinecraftCompressDecoder;
|
||||
import com.velocitypowered.proxy.protocol.netty.MinecraftCompressorAndLengthEncoder;
|
||||
import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder;
|
||||
import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder;
|
||||
import com.velocitypowered.proxy.protocol.netty.MinecraftVarintFrameDecoder;
|
||||
import com.velocitypowered.proxy.protocol.netty.MinecraftVarintLengthEncoder;
|
||||
import com.velocitypowered.proxy.protocol.netty.PlayPacketQueueInboundHandler;
|
||||
import com.velocitypowered.proxy.protocol.netty.PlayPacketQueueOutboundHandler;
|
||||
@ -369,11 +368,6 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
|
||||
ensureInEventLoop();
|
||||
|
||||
this.state = state;
|
||||
final MinecraftVarintFrameDecoder frameDecoder = this.channel.pipeline()
|
||||
.get(MinecraftVarintFrameDecoder.class);
|
||||
if (frameDecoder != null) {
|
||||
frameDecoder.setState(state);
|
||||
}
|
||||
// If the connection is LEGACY (<1.6), the decoder and encoder are not set.
|
||||
final MinecraftEncoder minecraftEncoder = this.channel.pipeline()
|
||||
.get(MinecraftEncoder.class);
|
||||
|
||||
@ -34,6 +34,8 @@ import com.velocitypowered.api.event.player.ServerResourcePackSendEvent;
|
||||
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
|
||||
import com.velocitypowered.api.proxy.messages.LegacyChannelIdentifier;
|
||||
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
|
||||
import com.velocitypowered.api.proxy.player.ResourcePackInfo;
|
||||
import com.velocitypowered.proxy.VelocityServer;
|
||||
import com.velocitypowered.proxy.command.CommandGraphInjector;
|
||||
@ -47,7 +49,6 @@ import com.velocitypowered.proxy.connection.util.ConnectionMessages;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||
import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder;
|
||||
import com.velocitypowered.proxy.protocol.netty.MinecraftVarintFrameDecoder;
|
||||
import com.velocitypowered.proxy.protocol.packet.AvailableCommandsPacket;
|
||||
import com.velocitypowered.proxy.protocol.packet.BossBarPacket;
|
||||
import com.velocitypowered.proxy.protocol.packet.BundleDelimiterPacket;
|
||||
@ -150,7 +151,6 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
MinecraftConnection smc = serverConn.ensureConnected();
|
||||
smc.setAutoReading(false);
|
||||
// Even when not auto reading messages are still decoded. Decode them with the correct state
|
||||
smc.getChannel().pipeline().get(MinecraftVarintFrameDecoder.class).setState(StateRegistry.CONFIG);
|
||||
smc.getChannel().pipeline().get(MinecraftDecoder.class).setState(StateRegistry.CONFIG);
|
||||
serverConn.getPlayer().switchToConfigState();
|
||||
return true;
|
||||
@ -290,31 +290,14 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Register and unregister packets are simply forwarded to the server as-is.
|
||||
if (PluginMessageUtil.isRegister(packet) || PluginMessageUtil.isUnregister(packet)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (PluginMessageUtil.isMcBrand(packet)) {
|
||||
PluginMessagePacket rewritten = PluginMessageUtil
|
||||
.rewriteMinecraftBrand(packet,
|
||||
server.getVersion(), playerConnection.getProtocolVersion());
|
||||
playerConnection.write(rewritten);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (serverConn.getPhase().handle(serverConn, serverConn.getPlayer(), packet)) {
|
||||
// Handled.
|
||||
return true;
|
||||
}
|
||||
|
||||
ChannelIdentifier id = server.getChannelRegistrar().getFromId(packet.getChannel());
|
||||
if (id == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
byte[] copy = ByteBufUtil.getBytes(packet.content());
|
||||
PluginMessageEvent event = new PluginMessageEvent(serverConn, serverConn.getPlayer(), id, copy);
|
||||
String channel = packet.getChannel();
|
||||
PluginMessageEvent event = new PluginMessageEvent(serverConn, serverConn.getPlayer(), channel.indexOf(':') == -1 ? new LegacyChannelIdentifier(channel) : MinecraftChannelIdentifier.from(channel), copy);
|
||||
server.getEventManager().fire(event).thenAcceptAsync(pme -> {
|
||||
if (pme.getResult().isAllowed() && !playerConnection.isClosed()) {
|
||||
PluginMessagePacket copied = new PluginMessagePacket(
|
||||
|
||||
@ -40,7 +40,6 @@ import com.velocitypowered.proxy.connection.util.ConnectionRequestResults.Impl;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||
import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder;
|
||||
import com.velocitypowered.proxy.protocol.netty.MinecraftVarintFrameDecoder;
|
||||
import com.velocitypowered.proxy.protocol.packet.ClientboundCookieRequestPacket;
|
||||
import com.velocitypowered.proxy.protocol.packet.ClientboundStoreCookiePacket;
|
||||
import com.velocitypowered.proxy.protocol.packet.DisconnectPacket;
|
||||
@ -233,7 +232,6 @@ public class ConfigSessionHandler implements MinecraftSessionHandler {
|
||||
final ConnectedPlayer player = serverConn.getPlayer();
|
||||
final ClientConfigSessionHandler configHandler = (ClientConfigSessionHandler) player.getConnection().getActiveSessionHandler();
|
||||
|
||||
smc.getChannel().pipeline().get(MinecraftVarintFrameDecoder.class).setState(StateRegistry.PLAY);
|
||||
smc.getChannel().pipeline().get(MinecraftDecoder.class).setState(StateRegistry.PLAY);
|
||||
//noinspection DataFlowIssue
|
||||
configHandler.handleBackendFinishUpdate(serverConn).thenRunAsync(() -> {
|
||||
|
||||
@ -170,11 +170,7 @@ public class ClientConfigSessionHandler implements MinecraftSessionHandler {
|
||||
@Override
|
||||
public boolean handle(KnownPacksPacket packet) {
|
||||
callConfigurationEvent().thenRun(() -> {
|
||||
VelocityServerConnection targetServer =
|
||||
player.getConnectionInFlightOrConnectedServer();
|
||||
if (targetServer != null) {
|
||||
targetServer.ensureConnected().write(packet);
|
||||
}
|
||||
player.getConnectionInFlightOrConnectedServer().ensureConnected().write(packet);
|
||||
}).exceptionally(ex -> {
|
||||
logger.error("Error forwarding known packs response to backend:", ex);
|
||||
return null;
|
||||
|
||||
@ -30,6 +30,8 @@ import com.velocitypowered.api.event.player.TabCompleteEvent;
|
||||
import com.velocitypowered.api.event.player.configuration.PlayerEnteredConfigurationEvent;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
|
||||
import com.velocitypowered.api.proxy.messages.LegacyChannelIdentifier;
|
||||
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
|
||||
import com.velocitypowered.proxy.VelocityServer;
|
||||
import com.velocitypowered.proxy.connection.ConnectionTypes;
|
||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
||||
@ -339,43 +341,25 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
}
|
||||
|
||||
if (!player.getPhase().handle(player, packet, serverConn)) {
|
||||
ChannelIdentifier id = server.getChannelRegistrar().getFromId(packet.getChannel());
|
||||
if (id == null) {
|
||||
// We don't have any plugins listening on this channel, process the packet now.
|
||||
if (!player.getPhase().consideredComplete() || !serverConn.getPhase()
|
||||
.consideredComplete()) {
|
||||
// The client is trying to send messages too early. This is primarily caused by mods,
|
||||
// but further aggravated by Velocity. To work around these issues, we will queue any
|
||||
// non-FML handshake messages to be sent once the FML handshake has completed or the
|
||||
// JoinGame packet has been received by the proxy, whichever comes first.
|
||||
//
|
||||
// We also need to make sure to retain these packets, so they can be flushed
|
||||
// appropriately.
|
||||
loginPluginMessages.add(packet.retain());
|
||||
} else {
|
||||
// The connection is ready, send the packet now.
|
||||
backendConn.write(packet.retain());
|
||||
}
|
||||
} else {
|
||||
byte[] copy = ByteBufUtil.getBytes(packet.content());
|
||||
PluginMessageEvent event = new PluginMessageEvent(player, serverConn, id, copy);
|
||||
server.getEventManager().fire(event).thenAcceptAsync(pme -> {
|
||||
if (pme.getResult().isAllowed()) {
|
||||
PluginMessagePacket message = new PluginMessagePacket(packet.getChannel(),
|
||||
Unpooled.wrappedBuffer(copy));
|
||||
if (!player.getPhase().consideredComplete() || !serverConn.getPhase()
|
||||
.consideredComplete()) {
|
||||
// We're still processing the connection (see above), enqueue the packet for now.
|
||||
loginPluginMessages.add(message.retain());
|
||||
} else {
|
||||
backendConn.write(message);
|
||||
}
|
||||
byte[] copy = ByteBufUtil.getBytes(packet.content());
|
||||
String channel = packet.getChannel();
|
||||
PluginMessageEvent event = new PluginMessageEvent(player, serverConn, channel.indexOf(':') == -1 ? new LegacyChannelIdentifier(channel) : MinecraftChannelIdentifier.from(channel), copy);
|
||||
server.getEventManager().fire(event).thenAcceptAsync(pme -> {
|
||||
if (pme.getResult().isAllowed()) {
|
||||
PluginMessagePacket message = new PluginMessagePacket(packet.getChannel(),
|
||||
Unpooled.wrappedBuffer(copy));
|
||||
if (!player.getPhase().consideredComplete() || !serverConn.getPhase()
|
||||
.consideredComplete()) {
|
||||
// We're still processing the connection (see above), enqueue the packet for now.
|
||||
loginPluginMessages.add(message.retain());
|
||||
} else {
|
||||
backendConn.write(message);
|
||||
}
|
||||
}, backendConn.eventLoop()).exceptionally((ex) -> {
|
||||
logger.error("Exception while handling plugin message packet for {}", player, ex);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
}, backendConn.eventLoop()).exceptionally((ex) -> {
|
||||
logger.error("Exception while handling plugin message packet for {}", player, ex);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,7 +123,6 @@ import net.kyori.adventure.permission.PermissionChecker;
|
||||
import net.kyori.adventure.platform.facet.FacetPointers;
|
||||
import net.kyori.adventure.platform.facet.FacetPointers.Type;
|
||||
import net.kyori.adventure.pointer.Pointers;
|
||||
import net.kyori.adventure.pointer.PointersSupplier;
|
||||
import net.kyori.adventure.resource.ResourcePackInfoLike;
|
||||
import net.kyori.adventure.resource.ResourcePackRequest;
|
||||
import net.kyori.adventure.resource.ResourcePackRequestLike;
|
||||
@ -146,23 +145,14 @@ import org.jetbrains.annotations.NotNull;
|
||||
public class ConnectedPlayer implements MinecraftConnectionAssociation, Player, KeyIdentifiable,
|
||||
VelocityInboundConnection {
|
||||
|
||||
public static final int MAX_CLIENTSIDE_PLUGIN_CHANNELS = Integer.getInteger("velocity.max-clientside-plugin-channels", 1024);
|
||||
public static final int MAX_CLIENTSIDE_PLUGIN_CHANNELS = 1024;
|
||||
private static final PlainTextComponentSerializer PASS_THRU_TRANSLATE =
|
||||
PlainTextComponentSerializer.builder().flattener(TranslatableMapper.FLATTENER).build();
|
||||
static final PermissionProvider DEFAULT_PERMISSIONS = s -> PermissionFunction.ALWAYS_UNDEFINED;
|
||||
|
||||
private static final ComponentLogger logger = ComponentLogger.logger(ConnectedPlayer.class);
|
||||
|
||||
private static final @NotNull PointersSupplier<ConnectedPlayer> POINTERS_SUPPLIER =
|
||||
PointersSupplier.<ConnectedPlayer>builder()
|
||||
.resolving(Identity.UUID, Player::getUniqueId)
|
||||
.resolving(Identity.NAME, Player::getUsername)
|
||||
.resolving(Identity.DISPLAY_NAME, player -> Component.text(player.getUsername()))
|
||||
.resolving(Identity.LOCALE, Player::getEffectiveLocale)
|
||||
.resolving(PermissionChecker.POINTER, Player::getPermissionChecker)
|
||||
.resolving(FacetPointers.TYPE, player -> Type.PLAYER)
|
||||
.build();
|
||||
|
||||
private final Identity identity = new IdentityImpl();
|
||||
/**
|
||||
* The actual Minecraft connection. This is actually a wrapper object around the Netty channel.
|
||||
*/
|
||||
@ -191,6 +181,14 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
||||
private final ResourcePackHandler resourcePackHandler;
|
||||
private final BundleDelimiterHandler bundleHandler = new BundleDelimiterHandler(this);
|
||||
|
||||
private final @NotNull Pointers pointers =
|
||||
Player.super.pointers().toBuilder()
|
||||
.withDynamic(Identity.UUID, this::getUniqueId)
|
||||
.withDynamic(Identity.NAME, this::getUsername)
|
||||
.withDynamic(Identity.DISPLAY_NAME, () -> Component.text(this.getUsername()))
|
||||
.withDynamic(Identity.LOCALE, this::getEffectiveLocale)
|
||||
.withStatic(PermissionChecker.POINTER, getPermissionChecker())
|
||||
.withStatic(FacetPointers.TYPE, Type.PLAYER).build();
|
||||
private @Nullable String clientBrand;
|
||||
private @Nullable Locale effectiveLocale;
|
||||
private final @Nullable IdentifiedKey playerKey;
|
||||
@ -259,7 +257,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
||||
|
||||
@Override
|
||||
public @NonNull Identity identity() {
|
||||
return Identity.identity(this.getUniqueId());
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -365,7 +363,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
||||
|
||||
@Override
|
||||
public @NotNull Pointers pointers() {
|
||||
return POINTERS_SUPPLIER.view(this);
|
||||
return this.pointers;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -398,20 +396,14 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the message in the user's locale, falling back to the default locale if not set.
|
||||
* Translates the message in the user's locale.
|
||||
*
|
||||
* @param message the message to translate
|
||||
* @return the translated message
|
||||
*/
|
||||
public Component translateMessage(Component message) {
|
||||
Locale locale = this.getEffectiveLocale();
|
||||
if (locale == null && settings != null) {
|
||||
locale = settings.getLocale();
|
||||
}
|
||||
if (locale == null) {
|
||||
locale = Locale.getDefault();
|
||||
}
|
||||
locale = ClosestLocaleMatcher.INSTANCE.lookupClosest(locale);
|
||||
Locale locale = ClosestLocaleMatcher.INSTANCE
|
||||
.lookupClosest(getEffectiveLocale() == null ? Locale.getDefault() : getEffectiveLocale());
|
||||
return GlobalTranslator.render(message, locale);
|
||||
}
|
||||
|
||||
@ -1369,6 +1361,14 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
||||
return playerKey;
|
||||
}
|
||||
|
||||
private class IdentityImpl implements Identity {
|
||||
|
||||
@Override
|
||||
public @NonNull UUID uuid() {
|
||||
return ConnectedPlayer.this.getUniqueId();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolState getProtocolState() {
|
||||
return connection.getState().toProtocolState();
|
||||
|
||||
@ -51,7 +51,7 @@ public class BackendChannelInitializer extends ChannelInitializer<Channel> {
|
||||
@Override
|
||||
protected void initChannel(Channel ch) {
|
||||
ch.pipeline()
|
||||
.addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder(ProtocolUtils.Direction.CLIENTBOUND))
|
||||
.addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder())
|
||||
.addLast(READ_TIMEOUT,
|
||||
new ReadTimeoutHandler(server.getConfiguration().getReadTimeout(),
|
||||
TimeUnit.MILLISECONDS))
|
||||
|
||||
@ -58,7 +58,7 @@ public class ServerChannelInitializer extends ChannelInitializer<Channel> {
|
||||
protected void initChannel(final Channel ch) {
|
||||
ch.pipeline()
|
||||
.addLast(LEGACY_PING_DECODER, new LegacyPingDecoder())
|
||||
.addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder(ProtocolUtils.Direction.SERVERBOUND))
|
||||
.addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder())
|
||||
.addLast(READ_TIMEOUT,
|
||||
new ReadTimeoutHandler(this.server.getConfiguration().getReadTimeout(),
|
||||
TimeUnit.MILLISECONDS))
|
||||
|
||||
@ -116,7 +116,7 @@ public enum TransportType {
|
||||
return NIO;
|
||||
}
|
||||
|
||||
if (IoUring.isAvailable() && !Boolean.getBoolean("velocity.disable-iouring-transport")) {
|
||||
if (IoUring.isAvailable() && Boolean.getBoolean("velocity.enable-iouring-transport")) {
|
||||
return IO_URING;
|
||||
}
|
||||
|
||||
|
||||
@ -47,7 +47,7 @@ import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.json.JSONOptions;
|
||||
import net.kyori.adventure.text.serializer.json.legacyimpl.NBTLegacyHoverEventSerializer;
|
||||
import net.kyori.option.OptionSchema;
|
||||
import net.kyori.option.OptionState;
|
||||
|
||||
/**
|
||||
* Utilities for writing and reading data in the Minecraft protocol.
|
||||
@ -60,11 +60,10 @@ public enum ProtocolUtils {
|
||||
.downsampleColors()
|
||||
.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get())
|
||||
.options(
|
||||
OptionSchema.globalSchema().stateBuilder()
|
||||
OptionState.optionState()
|
||||
// before 1.16
|
||||
.value(JSONOptions.EMIT_RGB, Boolean.FALSE)
|
||||
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.VALUE_FIELD)
|
||||
.value(JSONOptions.EMIT_CLICK_EVENT_TYPE, JSONOptions.ClickEventValueMode.CAMEL_CASE)
|
||||
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.LEGACY_ONLY)
|
||||
// before 1.20.3
|
||||
.value(JSONOptions.EMIT_COMPACT_TEXT_COMPONENT, Boolean.FALSE)
|
||||
.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, Boolean.FALSE)
|
||||
@ -76,12 +75,10 @@ public enum ProtocolUtils {
|
||||
GsonComponentSerializer.builder()
|
||||
.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get())
|
||||
.options(
|
||||
OptionSchema.globalSchema().stateBuilder()
|
||||
OptionState.optionState()
|
||||
// after 1.16
|
||||
.value(JSONOptions.EMIT_RGB, Boolean.TRUE)
|
||||
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.CAMEL_CASE)
|
||||
.value(JSONOptions.EMIT_CLICK_EVENT_TYPE, JSONOptions.ClickEventValueMode.CAMEL_CASE)
|
||||
.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_KEY_AS_TYPE_AND_UUID_AS_ID, true)
|
||||
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.MODERN_ONLY)
|
||||
// before 1.20.3
|
||||
.value(JSONOptions.EMIT_COMPACT_TEXT_COMPONENT, Boolean.FALSE)
|
||||
.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, Boolean.FALSE)
|
||||
@ -89,37 +86,17 @@ public enum ProtocolUtils {
|
||||
.build()
|
||||
)
|
||||
.build();
|
||||
private static final GsonComponentSerializer PRE_1_21_5_SERIALIZER =
|
||||
GsonComponentSerializer.builder()
|
||||
.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get())
|
||||
.options(
|
||||
OptionSchema.globalSchema().stateBuilder()
|
||||
// after 1.16
|
||||
.value(JSONOptions.EMIT_RGB, Boolean.TRUE)
|
||||
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.CAMEL_CASE)
|
||||
.value(JSONOptions.EMIT_CLICK_EVENT_TYPE, JSONOptions.ClickEventValueMode.CAMEL_CASE)
|
||||
.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_KEY_AS_TYPE_AND_UUID_AS_ID, true)
|
||||
// after 1.20.3
|
||||
.value(JSONOptions.EMIT_COMPACT_TEXT_COMPONENT, Boolean.TRUE)
|
||||
.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, Boolean.TRUE)
|
||||
.value(JSONOptions.VALIDATE_STRICT_EVENTS, Boolean.TRUE)
|
||||
.build()
|
||||
)
|
||||
.build();
|
||||
private static final GsonComponentSerializer MODERN_SERIALIZER =
|
||||
GsonComponentSerializer.builder()
|
||||
.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get())
|
||||
.options(
|
||||
OptionSchema.globalSchema().stateBuilder()
|
||||
OptionState.optionState()
|
||||
// after 1.16
|
||||
.value(JSONOptions.EMIT_RGB, Boolean.TRUE)
|
||||
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.SNAKE_CASE)
|
||||
.value(JSONOptions.EMIT_CLICK_EVENT_TYPE, JSONOptions.ClickEventValueMode.SNAKE_CASE)
|
||||
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.MODERN_ONLY)
|
||||
// after 1.20.3
|
||||
.value(JSONOptions.EMIT_COMPACT_TEXT_COMPONENT, Boolean.TRUE)
|
||||
.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, Boolean.TRUE)
|
||||
// after 1.21.5
|
||||
.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_KEY_AS_TYPE_AND_UUID_AS_ID, Boolean.FALSE)
|
||||
.value(JSONOptions.VALIDATE_STRICT_EVENTS, Boolean.TRUE)
|
||||
.build()
|
||||
)
|
||||
@ -736,11 +713,8 @@ public enum ProtocolUtils {
|
||||
* @return the appropriate {@link GsonComponentSerializer}
|
||||
*/
|
||||
public static GsonComponentSerializer getJsonChatSerializer(ProtocolVersion version) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_21_5)) {
|
||||
return MODERN_SERIALIZER;
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_3)) {
|
||||
return PRE_1_21_5_SERIALIZER;
|
||||
return MODERN_SERIALIZER;
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
return PRE_1_20_3_SERIALIZER;
|
||||
|
||||
@ -40,7 +40,6 @@ import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21;
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21_2;
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21_4;
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21_5;
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21_6;
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_7_2;
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_8;
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_9;
|
||||
@ -88,6 +87,7 @@ import com.velocitypowered.proxy.protocol.packet.StatusResponsePacket;
|
||||
import com.velocitypowered.proxy.protocol.packet.TabCompleteRequestPacket;
|
||||
import com.velocitypowered.proxy.protocol.packet.TabCompleteResponsePacket;
|
||||
import com.velocitypowered.proxy.protocol.packet.TransferPacket;
|
||||
import com.velocitypowered.proxy.protocol.packet.UpdateTeamsPacket;
|
||||
import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfoPacket;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ChatAcknowledgementPacket;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.PlayerChatCompletionPacket;
|
||||
@ -257,8 +257,7 @@ public enum StateRegistry {
|
||||
map(0x09, MINECRAFT_1_19_4, false),
|
||||
map(0x0A, MINECRAFT_1_20_2, false),
|
||||
map(0x0B, MINECRAFT_1_20_5, false),
|
||||
map(0x0D, MINECRAFT_1_21_2, false),
|
||||
map(0x0E, MINECRAFT_1_21_6, false));
|
||||
map(0x0D, MINECRAFT_1_21_2, false));
|
||||
serverbound.register(
|
||||
LegacyChatPacket.class,
|
||||
LegacyChatPacket::new,
|
||||
@ -271,8 +270,7 @@ public enum StateRegistry {
|
||||
ChatAcknowledgementPacket.class,
|
||||
ChatAcknowledgementPacket::new,
|
||||
map(0x03, MINECRAFT_1_19_3, false),
|
||||
map(0x04, MINECRAFT_1_21_2, false),
|
||||
map(0x05, MINECRAFT_1_21_6, false));
|
||||
map(0x04, MINECRAFT_1_21_2, false));
|
||||
serverbound.register(KeyedPlayerCommandPacket.class, KeyedPlayerCommandPacket::new,
|
||||
map(0x03, MINECRAFT_1_19, false),
|
||||
map(0x04, MINECRAFT_1_19_1, MINECRAFT_1_19_1, false));
|
||||
@ -282,19 +280,16 @@ public enum StateRegistry {
|
||||
serverbound.register(SessionPlayerCommandPacket.class, SessionPlayerCommandPacket::new,
|
||||
map(0x04, MINECRAFT_1_19_3, false),
|
||||
map(0x05, MINECRAFT_1_20_5, false),
|
||||
map(0x06, MINECRAFT_1_21_2, false),
|
||||
map(0x07, MINECRAFT_1_21_6, false));
|
||||
map(0x06, MINECRAFT_1_21_2, false));
|
||||
serverbound.register(UnsignedPlayerCommandPacket.class, UnsignedPlayerCommandPacket::new,
|
||||
map(0x04, MINECRAFT_1_20_5, false),
|
||||
map(0x05, MINECRAFT_1_21_2, false),
|
||||
map(0x06, MINECRAFT_1_21_6, false));
|
||||
map(0x05, MINECRAFT_1_21_2, false));
|
||||
serverbound.register(
|
||||
SessionPlayerChatPacket.class,
|
||||
SessionPlayerChatPacket::new,
|
||||
map(0x05, MINECRAFT_1_19_3, false),
|
||||
map(0x06, MINECRAFT_1_20_5, false),
|
||||
map(0x07, MINECRAFT_1_21_2, false),
|
||||
map(0x08, MINECRAFT_1_21_6, false));
|
||||
map(0x07, MINECRAFT_1_21_2, false));
|
||||
serverbound.register(
|
||||
ClientSettingsPacket.class,
|
||||
ClientSettingsPacket::new,
|
||||
@ -309,13 +304,11 @@ public enum StateRegistry {
|
||||
map(0x08, MINECRAFT_1_19_4, false),
|
||||
map(0x09, MINECRAFT_1_20_2, false),
|
||||
map(0x0A, MINECRAFT_1_20_5, false),
|
||||
map(0x0C, MINECRAFT_1_21_2, false),
|
||||
map(0x0D, MINECRAFT_1_21_6, false));
|
||||
map(0x0C, MINECRAFT_1_21_2, false));
|
||||
serverbound.register(
|
||||
ServerboundCookieResponsePacket.class, ServerboundCookieResponsePacket::new,
|
||||
map(0x11, MINECRAFT_1_20_5, false),
|
||||
map(0x13, MINECRAFT_1_21_2, false),
|
||||
map(0x14, MINECRAFT_1_21_6, false));
|
||||
map(0x13, MINECRAFT_1_21_2, false));
|
||||
serverbound.register(
|
||||
PluginMessagePacket.class,
|
||||
PluginMessagePacket::new,
|
||||
@ -333,8 +326,7 @@ public enum StateRegistry {
|
||||
map(0x0F, MINECRAFT_1_20_2, false),
|
||||
map(0x10, MINECRAFT_1_20_3, false),
|
||||
map(0x12, MINECRAFT_1_20_5, false),
|
||||
map(0x14, MINECRAFT_1_21_2, false),
|
||||
map(0x15, MINECRAFT_1_21_6, false));
|
||||
map(0x14, MINECRAFT_1_21_2, false));
|
||||
serverbound.register(
|
||||
KeepAlivePacket.class,
|
||||
KeepAlivePacket::new,
|
||||
@ -353,8 +345,7 @@ public enum StateRegistry {
|
||||
map(0x14, MINECRAFT_1_20_2, false),
|
||||
map(0x15, MINECRAFT_1_20_3, false),
|
||||
map(0x18, MINECRAFT_1_20_5, false),
|
||||
map(0x1A, MINECRAFT_1_21_2, false),
|
||||
map(0x1B, MINECRAFT_1_21_6, false));
|
||||
map(0x1A, MINECRAFT_1_21_2, false));
|
||||
serverbound.register(
|
||||
ResourcePackResponsePacket.class,
|
||||
ResourcePackResponsePacket::new,
|
||||
@ -371,14 +362,12 @@ public enum StateRegistry {
|
||||
map(0x28, MINECRAFT_1_20_3, false),
|
||||
map(0x2B, MINECRAFT_1_20_5, false),
|
||||
map(0x2D, MINECRAFT_1_21_2, false),
|
||||
map(0x2F, MINECRAFT_1_21_4, false),
|
||||
map(0x30, MINECRAFT_1_21_6, false));
|
||||
map(0x2F, MINECRAFT_1_21_4, false));
|
||||
serverbound.register(
|
||||
FinishedUpdatePacket.class, () -> FinishedUpdatePacket.INSTANCE,
|
||||
map(0x0B, MINECRAFT_1_20_2, false),
|
||||
map(0x0C, MINECRAFT_1_20_5, false),
|
||||
map(0x0E, MINECRAFT_1_21_2, false),
|
||||
map(0x0F, MINECRAFT_1_21_6, false));
|
||||
map(0x0E, MINECRAFT_1_21_2, false));
|
||||
|
||||
clientbound.register(
|
||||
BossBarPacket.class,
|
||||
@ -743,6 +732,22 @@ public enum StateRegistry {
|
||||
ClientboundServerLinksPacket::new,
|
||||
map(0x7B, MINECRAFT_1_21, false),
|
||||
map(0x82, MINECRAFT_1_21_2, false));
|
||||
clientbound.register(UpdateTeamsPacket.class, UpdateTeamsPacket::new,
|
||||
map(0x41, ProtocolVersion.MINECRAFT_1_9, true),
|
||||
map(0x43, ProtocolVersion.MINECRAFT_1_12, true),
|
||||
map(0x44, ProtocolVersion.MINECRAFT_1_12_1, true),
|
||||
map(0x47, ProtocolVersion.MINECRAFT_1_13, true),
|
||||
map(0x4B, ProtocolVersion.MINECRAFT_1_14, true),
|
||||
map(0x4C, ProtocolVersion.MINECRAFT_1_15, true),
|
||||
map(0x55, ProtocolVersion.MINECRAFT_1_17, true),
|
||||
map(0x58, ProtocolVersion.MINECRAFT_1_19_1, true),
|
||||
map(0x56, ProtocolVersion.MINECRAFT_1_19_3, true),
|
||||
map(0x5A, ProtocolVersion.MINECRAFT_1_19_4, true),
|
||||
map(0x5C, ProtocolVersion.MINECRAFT_1_20_2, true),
|
||||
map(0x5E, ProtocolVersion.MINECRAFT_1_20_3, true),
|
||||
map(0x60, ProtocolVersion.MINECRAFT_1_20_5, true),
|
||||
map(0x67, ProtocolVersion.MINECRAFT_1_21_2, true)
|
||||
);
|
||||
}
|
||||
},
|
||||
LOGIN {
|
||||
|
||||
@ -39,7 +39,6 @@ public class MinecraftCompressDecoder extends MessageToMessageDecoder<ByteBuf> {
|
||||
private static final int UNCOMPRESSED_CAP =
|
||||
Boolean.getBoolean("velocity.increased-compression-cap")
|
||||
? HARD_MAXIMUM_UNCOMPRESSED_SIZE : VANILLA_MAXIMUM_UNCOMPRESSED_SIZE;
|
||||
private static final boolean SKIP_COMPRESSION_VALIDATION = Boolean.getBoolean("velocity.skip-uncompressed-packet-size-validation");
|
||||
|
||||
private int threshold;
|
||||
private final VelocityCompressor compressor;
|
||||
@ -53,11 +52,9 @@ public class MinecraftCompressDecoder extends MessageToMessageDecoder<ByteBuf> {
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
||||
int claimedUncompressedSize = ProtocolUtils.readVarInt(in);
|
||||
if (claimedUncompressedSize == 0) {
|
||||
if (!SKIP_COMPRESSION_VALIDATION) {
|
||||
int actualUncompressedSize = in.readableBytes();
|
||||
checkFrame(actualUncompressedSize < threshold, "Actual uncompressed size %s is greater than"
|
||||
+ " threshold %s", actualUncompressedSize, threshold);
|
||||
}
|
||||
int actualUncompressedSize = in.readableBytes();
|
||||
checkFrame(actualUncompressedSize < threshold, "Actual uncompressed size %s is greater than"
|
||||
+ " threshold %s", actualUncompressedSize, threshold);
|
||||
// This message is not compressed.
|
||||
out.add(in.retain());
|
||||
return;
|
||||
|
||||
@ -135,7 +135,7 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter {
|
||||
|
||||
private String getExtraConnectionDetail(int packetId) {
|
||||
return "Direction " + direction + " Protocol " + registry.version + " State " + state
|
||||
+ " ID 0x" + Integer.toHexString(packetId);
|
||||
+ " ID " + Integer.toHexString(packetId);
|
||||
}
|
||||
|
||||
public void setProtocolVersion(ProtocolVersion protocolVersion) {
|
||||
|
||||
@ -19,51 +19,21 @@ package com.velocitypowered.proxy.protocol.netty;
|
||||
|
||||
import static io.netty.util.ByteProcessor.FIND_NON_NUL;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
||||
import com.velocitypowered.proxy.util.except.QuietRuntimeException;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.CorruptedFrameException;
|
||||
import java.util.List;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Frames Minecraft server packets which are prefixed by a 21-bit VarInt encoding.
|
||||
*/
|
||||
public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(MinecraftVarintFrameDecoder.class);
|
||||
private static final QuietRuntimeException FRAME_DECODER_FAILED =
|
||||
new QuietRuntimeException("A packet frame decoder failed. For more information, launch "
|
||||
+ "Velocity with -Dvelocity.packet-decode-logging=true to see more.");
|
||||
private static final QuietDecoderException BAD_PACKET_LENGTH =
|
||||
new QuietDecoderException("Bad packet length");
|
||||
private static final QuietDecoderException VARINT_TOO_BIG =
|
||||
new QuietDecoderException("VarInt too big");
|
||||
private static final QuietDecoderException UNKNOWN_PACKET =
|
||||
new QuietDecoderException("Unknown packet");
|
||||
|
||||
private final ProtocolUtils.Direction direction;
|
||||
private final StateRegistry.PacketRegistry.ProtocolRegistry registry;
|
||||
private StateRegistry state;
|
||||
|
||||
/**
|
||||
* Creates a new {@code MinecraftVarintFrameDecoder} decoding packets from the specified {@code Direction}.
|
||||
*
|
||||
* @param direction the direction from which we decode from
|
||||
*/
|
||||
public MinecraftVarintFrameDecoder(ProtocolUtils.Direction direction) {
|
||||
this.direction = direction;
|
||||
this.registry = StateRegistry.HANDSHAKE.getProtocolRegistry(
|
||||
direction, ProtocolVersion.MINIMUM_VERSION);
|
||||
this.state = StateRegistry.HANDSHAKE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
|
||||
@ -92,43 +62,6 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
|
||||
throw BAD_PACKET_LENGTH;
|
||||
}
|
||||
|
||||
if (length > 0) {
|
||||
if (state == StateRegistry.HANDSHAKE && direction == ProtocolUtils.Direction.SERVERBOUND) {
|
||||
StateRegistry.PacketRegistry.ProtocolRegistry registry =
|
||||
state.getProtocolRegistry(direction, ProtocolVersion.MINIMUM_VERSION);
|
||||
|
||||
final int index = in.readerIndex();
|
||||
final int packetId = readRawVarInt21(in);
|
||||
// Index hasn't changed, we've read nothing
|
||||
if (index == in.readerIndex()) {
|
||||
in.resetReaderIndex();
|
||||
return;
|
||||
}
|
||||
final int payloadLength = length - ProtocolUtils.varIntBytes(packetId);
|
||||
|
||||
MinecraftPacket packet = registry.createPacket(packetId);
|
||||
|
||||
// We handle every packet in this phase, if you said something we don't know, something is really wrong
|
||||
if (packet == null) {
|
||||
throw UNKNOWN_PACKET;
|
||||
}
|
||||
|
||||
// We 'technically' have the incoming bytes of a payload here, and so, these can actually parse
|
||||
// the packet if needed, so, we'll take advantage of the existing methods
|
||||
int expectedMinLen = packet.expectedMinLength(in, direction, registry.version);
|
||||
int expectedMaxLen = packet.expectedMaxLength(in, direction, registry.version);
|
||||
if (expectedMaxLen != -1 && payloadLength > expectedMaxLen) {
|
||||
throw handleOverflow(packet, expectedMaxLen, in.readableBytes());
|
||||
}
|
||||
if (payloadLength < expectedMinLen) {
|
||||
throw handleUnderflow(packet, expectedMaxLen, in.readableBytes());
|
||||
}
|
||||
|
||||
|
||||
in.readerIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
// note that zero-length packets are ignored
|
||||
if (length > 0) {
|
||||
if (in.readableBytes() < length) {
|
||||
@ -139,16 +72,6 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
if (MinecraftDecoder.DEBUG) {
|
||||
LOGGER.atWarn()
|
||||
.withThrowable(cause)
|
||||
.log("Exception caught while decoding frame for {}", ctx.channel().remoteAddress());
|
||||
}
|
||||
super.exceptionCaught(ctx, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a VarInt from the buffer of up to 21 bits in size.
|
||||
*
|
||||
@ -218,26 +141,4 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
|
||||
}
|
||||
return result | (tmp & 0x7F) << 14;
|
||||
}
|
||||
|
||||
private Exception handleOverflow(MinecraftPacket packet, int expected, int actual) {
|
||||
if (MinecraftDecoder.DEBUG) {
|
||||
return new CorruptedFrameException("Packet sent for " + packet.getClass() + " was too "
|
||||
+ "big (expected " + expected + " bytes, got " + actual + " bytes)");
|
||||
} else {
|
||||
return FRAME_DECODER_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
private Exception handleUnderflow(MinecraftPacket packet, int expected, int actual) {
|
||||
if (MinecraftDecoder.DEBUG) {
|
||||
return new CorruptedFrameException("Packet sent for " + packet.getClass() + " was too "
|
||||
+ "small (expected " + expected + " bytes, got " + actual + " bytes)");
|
||||
} else {
|
||||
return FRAME_DECODER_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
public void setState(StateRegistry stateRegistry) {
|
||||
this.state = stateRegistry;
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,14 +50,12 @@ import java.util.Deque;
|
||||
import java.util.Iterator;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Predicate;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class AvailableCommandsPacket implements MinecraftPacket {
|
||||
|
||||
private static final Command<CommandSource> PLACEHOLDER_COMMAND = source -> 0;
|
||||
private static final Predicate<CommandSource> PLACEHOLDER_REQUIREMENT = source -> true;
|
||||
|
||||
private static final byte NODE_TYPE_ROOT = 0x00;
|
||||
private static final byte NODE_TYPE_LITERAL = 0x01;
|
||||
@ -67,7 +65,6 @@ public class AvailableCommandsPacket implements MinecraftPacket {
|
||||
private static final byte FLAG_EXECUTABLE = 0x04;
|
||||
private static final byte FLAG_IS_REDIRECT = 0x08;
|
||||
private static final byte FLAG_HAS_SUGGESTIONS = 0x10;
|
||||
private static final byte FLAG_IS_RESTRICTED = 0x20;
|
||||
|
||||
private @MonotonicNonNull RootCommandNode<CommandSource> rootNode;
|
||||
|
||||
@ -149,9 +146,6 @@ public class AvailableCommandsPacket implements MinecraftPacket {
|
||||
if (node.getCommand() != null) {
|
||||
flags |= FLAG_EXECUTABLE;
|
||||
}
|
||||
if (node.getRequirement() == PLACEHOLDER_REQUIREMENT) {
|
||||
flags |= FLAG_IS_RESTRICTED;
|
||||
}
|
||||
|
||||
if (node instanceof LiteralCommandNode<?>) {
|
||||
flags |= NODE_TYPE_LITERAL;
|
||||
@ -295,11 +289,6 @@ public class AvailableCommandsPacket implements MinecraftPacket {
|
||||
args.executes(PLACEHOLDER_COMMAND);
|
||||
}
|
||||
|
||||
// If restricted, add empty requirement
|
||||
if ((flags & FLAG_IS_RESTRICTED) != 0) {
|
||||
args.requires(PLACEHOLDER_REQUIREMENT);
|
||||
}
|
||||
|
||||
this.built = args.build();
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,16 +106,4 @@ public class HandshakePacket implements MinecraftPacket {
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int expectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
return 7;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
return 9 + (MAXIMUM_HOSTNAME_LENGTH * 3);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,233 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.protocol.packet;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class UpdateTeamsPacket implements MinecraftPacket {
|
||||
private String name;
|
||||
private Mode mode;
|
||||
|
||||
private Component displayName;
|
||||
private Component prefix;
|
||||
private Component suffix;
|
||||
private NameTagVisibility nameTagVisibility;
|
||||
private CollisionRule collisionRule;
|
||||
private int color;
|
||||
private byte friendlyFlags;
|
||||
|
||||
private List<String> players;
|
||||
|
||||
public UpdateTeamsPacket(String name, Mode mode, Component displayName, Component prefix, Component suffix, NameTagVisibility nameTagVisibility, CollisionRule collisionRule, int color, byte friendlyFlags, List<String> players) {
|
||||
this.name = name;
|
||||
this.mode = mode;
|
||||
this.displayName = displayName;
|
||||
this.prefix = prefix;
|
||||
this.suffix = suffix;
|
||||
this.nameTagVisibility = nameTagVisibility;
|
||||
this.collisionRule = collisionRule;
|
||||
this.color = color;
|
||||
this.friendlyFlags = friendlyFlags;
|
||||
this.players = players;
|
||||
}
|
||||
|
||||
public UpdateTeamsPacket() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
throw new UnsupportedOperationException("Packet is not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler minecraftSessionHandler) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeString(byteBuf, name);
|
||||
byteBuf.writeByte(mode.ordinal());
|
||||
|
||||
switch (mode) {
|
||||
case CREATE, UPDATE:
|
||||
new ComponentHolder(protocolVersion, displayName).write(byteBuf);
|
||||
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_13)) {
|
||||
new ComponentHolder(protocolVersion, prefix).write(byteBuf);
|
||||
new ComponentHolder(protocolVersion, suffix).write(byteBuf);
|
||||
}
|
||||
byteBuf.writeByte(friendlyFlags);
|
||||
ProtocolUtils.writeString(byteBuf, nameTagVisibility.getValue());
|
||||
ProtocolUtils.writeString(byteBuf, collisionRule.getValue());
|
||||
if (protocolVersion.greaterThan(ProtocolVersion.MINECRAFT_1_12_2)) {
|
||||
ProtocolUtils.writeVarInt(byteBuf, color);
|
||||
new ComponentHolder(protocolVersion, prefix).write(byteBuf);
|
||||
new ComponentHolder(protocolVersion, suffix).write(byteBuf);
|
||||
} else {
|
||||
byteBuf.writeByte((byte) color);
|
||||
}
|
||||
|
||||
ProtocolUtils.writeVarInt(byteBuf, players.size());
|
||||
for (String player : players) {
|
||||
ProtocolUtils.writeString(byteBuf, player);
|
||||
}
|
||||
break;
|
||||
case ADD_PLAYER, REMOVE_PLAYER:
|
||||
ProtocolUtils.writeVarInt(byteBuf, players.size());
|
||||
for (String player : players) {
|
||||
ProtocolUtils.writeString(byteBuf, player);
|
||||
}
|
||||
break;
|
||||
case REMOVE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Mode {
|
||||
CREATE,
|
||||
REMOVE,
|
||||
UPDATE,
|
||||
ADD_PLAYER,
|
||||
REMOVE_PLAYER,
|
||||
}
|
||||
|
||||
public enum NameTagVisibility {
|
||||
ALWAYS("always"),
|
||||
NEVER("never"),
|
||||
HIDE_FOR_OTHER_TEAMS("hideForOtherTeams"),
|
||||
HIDE_FOR_OWN_TEAM("hideForOwnTeam");
|
||||
|
||||
private final String value;
|
||||
|
||||
NameTagVisibility(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public enum CollisionRule {
|
||||
ALWAYS("always"),
|
||||
NEVER("never"),
|
||||
PUSH_OTHER_TEAMS("pushOtherTeams"),
|
||||
PUSH_OWN_TEAM("pushOwnTeam");
|
||||
|
||||
private final String value;
|
||||
|
||||
CollisionRule(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Mode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public Component getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public Component getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public Component getSuffix() {
|
||||
return suffix;
|
||||
}
|
||||
|
||||
public NameTagVisibility getNameTagVisibility() {
|
||||
return nameTagVisibility;
|
||||
}
|
||||
|
||||
public CollisionRule getCollisionRule() {
|
||||
return collisionRule;
|
||||
}
|
||||
|
||||
public int getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public byte getFriendlyFlags() {
|
||||
return friendlyFlags;
|
||||
}
|
||||
|
||||
public List<String> getPlayers() {
|
||||
return players;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setMode(Mode mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public void setDisplayName(Component displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public void setPrefix(Component prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public void setSuffix(Component suffix) {
|
||||
this.suffix = suffix;
|
||||
}
|
||||
|
||||
public void setNameTagVisibility(NameTagVisibility nameTagVisibility) {
|
||||
this.nameTagVisibility = nameTagVisibility;
|
||||
}
|
||||
|
||||
public void setCollisionRule(CollisionRule collisionRule) {
|
||||
this.collisionRule = collisionRule;
|
||||
}
|
||||
|
||||
public void setColor(int color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public void setFriendlyFlags(byte friendlyFlags) {
|
||||
this.friendlyFlags = friendlyFlags;
|
||||
}
|
||||
|
||||
public void setPlayers(List<String> players) {
|
||||
this.players = players;
|
||||
}
|
||||
}
|
||||
@ -23,7 +23,6 @@ import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_19_4;
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_20_3;
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_20_5;
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21_5;
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21_6;
|
||||
import static com.velocitypowered.proxy.protocol.packet.brigadier.ArgumentIdentifier.id;
|
||||
import static com.velocitypowered.proxy.protocol.packet.brigadier.ArgumentIdentifier.mapSet;
|
||||
import static com.velocitypowered.proxy.protocol.packet.brigadier.DoubleArgumentPropertySerializer.DOUBLE;
|
||||
@ -165,7 +164,6 @@ public class ArgumentPropertyRegistry {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Argument type identifier " + id + " unknown.");
|
||||
} else {
|
||||
String identifier = ProtocolUtils.readString(buf);
|
||||
for (ArgumentIdentifier i : byIdentifier.keySet()) {
|
||||
@ -209,79 +207,68 @@ public class ArgumentPropertyRegistry {
|
||||
empty(id("minecraft:item_stack", mapSet(MINECRAFT_1_19, 14)));
|
||||
empty(id("minecraft:item_predicate", mapSet(MINECRAFT_1_19, 15)));
|
||||
empty(id("minecraft:color", mapSet(MINECRAFT_1_19, 16)));
|
||||
empty(id("minecraft:component", mapSet(MINECRAFT_1_21_6, 18), mapSet(MINECRAFT_1_19, 17)));
|
||||
empty(id("minecraft:style", mapSet(MINECRAFT_1_21_6, 19), mapSet(MINECRAFT_1_20_3, 18))); // added 1.20.3
|
||||
empty(id("minecraft:message", mapSet(MINECRAFT_1_21_6, 20), mapSet(MINECRAFT_1_20_3, 19), mapSet(MINECRAFT_1_19, 18)));
|
||||
empty(id("minecraft:nbt_compound_tag", mapSet(MINECRAFT_1_21_6, 21), mapSet(MINECRAFT_1_20_3, 20), mapSet(MINECRAFT_1_19, 19))); // added in 1.14
|
||||
empty(id("minecraft:nbt_tag", mapSet(MINECRAFT_1_21_6, 22), mapSet(MINECRAFT_1_20_3, 21), mapSet(MINECRAFT_1_19, 20))); // added in 1.14
|
||||
empty(id("minecraft:nbt_path", mapSet(MINECRAFT_1_21_6, 23), mapSet(MINECRAFT_1_20_3, 22), mapSet(MINECRAFT_1_19, 21)));
|
||||
empty(id("minecraft:objective", mapSet(MINECRAFT_1_21_6, 24), mapSet(MINECRAFT_1_20_3, 23), mapSet(MINECRAFT_1_19, 22)));
|
||||
empty(id("minecraft:objective_criteria", mapSet(MINECRAFT_1_21_6, 25), mapSet(MINECRAFT_1_20_3, 24), mapSet(MINECRAFT_1_19, 23)));
|
||||
empty(id("minecraft:operation", mapSet(MINECRAFT_1_21_6, 26), mapSet(MINECRAFT_1_20_3, 25), mapSet(MINECRAFT_1_19, 24)));
|
||||
empty(id("minecraft:particle", mapSet(MINECRAFT_1_21_6, 27), mapSet(MINECRAFT_1_20_3, 26), mapSet(MINECRAFT_1_19, 25)));
|
||||
empty(id("minecraft:angle", mapSet(MINECRAFT_1_21_6, 28), mapSet(MINECRAFT_1_20_3, 27), mapSet(MINECRAFT_1_19, 26))); // added in 1.16.2
|
||||
empty(id("minecraft:rotation", mapSet(MINECRAFT_1_21_6, 29), mapSet(MINECRAFT_1_20_3, 28), mapSet(MINECRAFT_1_19, 27)));
|
||||
empty(id("minecraft:scoreboard_slot", mapSet(MINECRAFT_1_21_6, 30), mapSet(MINECRAFT_1_20_3, 29), mapSet(MINECRAFT_1_19, 28)));
|
||||
empty(id("minecraft:score_holder", mapSet(MINECRAFT_1_21_6, 31), mapSet(MINECRAFT_1_20_3, 30), mapSet(MINECRAFT_1_19, 29)),
|
||||
ByteArgumentPropertySerializer.BYTE);
|
||||
empty(id("minecraft:swizzle", mapSet(MINECRAFT_1_21_6, 32), mapSet(MINECRAFT_1_20_3, 31), mapSet(MINECRAFT_1_19, 30)));
|
||||
empty(id("minecraft:team", mapSet(MINECRAFT_1_21_6, 33), mapSet(MINECRAFT_1_20_3, 32), mapSet(MINECRAFT_1_19, 31)));
|
||||
empty(id("minecraft:item_slot", mapSet(MINECRAFT_1_21_6, 34), mapSet(MINECRAFT_1_20_3, 33), mapSet(MINECRAFT_1_19, 32)));
|
||||
empty(id("minecraft:item_slots", mapSet(MINECRAFT_1_21_6, 35), mapSet(MINECRAFT_1_20_5, 34))); // added 1.20.5
|
||||
empty(id("minecraft:resource_location", mapSet(MINECRAFT_1_21_6, 36), mapSet(MINECRAFT_1_20_5, 35), mapSet(MINECRAFT_1_20_3, 34),
|
||||
mapSet(MINECRAFT_1_19, 33)));
|
||||
empty(id("minecraft:component", mapSet(MINECRAFT_1_19, 17)));
|
||||
empty(id("minecraft:style", mapSet(MINECRAFT_1_20_3, 18))); // added 1.20.3
|
||||
empty(id("minecraft:message", mapSet(MINECRAFT_1_20_3, 19), mapSet(MINECRAFT_1_19, 18)));
|
||||
empty(id("minecraft:nbt_compound_tag", mapSet(MINECRAFT_1_20_3, 20), mapSet(MINECRAFT_1_19, 19))); // added in 1.14
|
||||
empty(id("minecraft:nbt_tag", mapSet(MINECRAFT_1_20_3, 21), mapSet(MINECRAFT_1_19, 20))); // added in 1.14
|
||||
empty(id("minecraft:nbt_path", mapSet(MINECRAFT_1_20_3, 22), mapSet(MINECRAFT_1_19, 21)));
|
||||
empty(id("minecraft:objective", mapSet(MINECRAFT_1_20_3, 23), mapSet(MINECRAFT_1_19, 22)));
|
||||
empty(id("minecraft:objective_criteria", mapSet(MINECRAFT_1_20_3, 24), mapSet(MINECRAFT_1_19, 23)));
|
||||
empty(id("minecraft:operation", mapSet(MINECRAFT_1_20_3, 25), mapSet(MINECRAFT_1_19, 24)));
|
||||
empty(id("minecraft:particle", mapSet(MINECRAFT_1_20_3, 26), mapSet(MINECRAFT_1_19, 25)));
|
||||
empty(id("minecraft:angle", mapSet(MINECRAFT_1_20_3, 27), mapSet(MINECRAFT_1_19, 26))); // added in 1.16.2
|
||||
empty(id("minecraft:rotation", mapSet(MINECRAFT_1_20_3, 28), mapSet(MINECRAFT_1_19, 27)));
|
||||
empty(id("minecraft:scoreboard_slot", mapSet(MINECRAFT_1_20_3, 29), mapSet(MINECRAFT_1_19, 28)));
|
||||
empty(id("minecraft:score_holder", mapSet(MINECRAFT_1_20_3, 30), mapSet(MINECRAFT_1_19, 29)), ByteArgumentPropertySerializer.BYTE);
|
||||
empty(id("minecraft:swizzle", mapSet(MINECRAFT_1_20_3, 31), mapSet(MINECRAFT_1_19, 30)));
|
||||
empty(id("minecraft:team", mapSet(MINECRAFT_1_20_3, 32), mapSet(MINECRAFT_1_19, 31)));
|
||||
empty(id("minecraft:item_slot", mapSet(MINECRAFT_1_20_3, 33), mapSet(MINECRAFT_1_19, 32)));
|
||||
empty(id("minecraft:item_slots", mapSet(MINECRAFT_1_20_5, 34))); // added 1.20.5
|
||||
empty(id("minecraft:resource_location", mapSet(MINECRAFT_1_20_5, 35), mapSet(MINECRAFT_1_20_3, 34), mapSet(MINECRAFT_1_19, 33)));
|
||||
empty(id("minecraft:mob_effect", mapSet(MINECRAFT_1_19_3, -1), mapSet(MINECRAFT_1_19, 34)));
|
||||
empty(id("minecraft:function", mapSet(MINECRAFT_1_21_6, 37), mapSet(MINECRAFT_1_20_5, 36), mapSet(MINECRAFT_1_20_3, 35),
|
||||
mapSet(MINECRAFT_1_19_3, 34), mapSet(MINECRAFT_1_19, 35)));
|
||||
empty(id("minecraft:entity_anchor", mapSet(MINECRAFT_1_21_6, 38), mapSet(MINECRAFT_1_20_5, 37), mapSet(MINECRAFT_1_20_3, 36),
|
||||
mapSet(MINECRAFT_1_19_3, 35), mapSet(MINECRAFT_1_19, 36)));
|
||||
empty(id("minecraft:int_range", mapSet(MINECRAFT_1_21_6, 39), mapSet(MINECRAFT_1_20_5, 38), mapSet(MINECRAFT_1_20_3, 37),
|
||||
mapSet(MINECRAFT_1_19_3, 36), mapSet(MINECRAFT_1_19, 37)));
|
||||
empty(id("minecraft:float_range", mapSet(MINECRAFT_1_21_6, 40), mapSet(MINECRAFT_1_20_5, 39), mapSet(MINECRAFT_1_20_3, 38),
|
||||
mapSet(MINECRAFT_1_19_3, 37), mapSet(MINECRAFT_1_19, 38)));
|
||||
empty(id("minecraft:function", mapSet(MINECRAFT_1_20_5, 36), mapSet(MINECRAFT_1_20_3, 35), mapSet(MINECRAFT_1_19_3, 34),
|
||||
mapSet(MINECRAFT_1_19, 35)));
|
||||
empty(id("minecraft:entity_anchor", mapSet(MINECRAFT_1_20_5, 37), mapSet(MINECRAFT_1_20_3, 36), mapSet(MINECRAFT_1_19_3, 35),
|
||||
mapSet(MINECRAFT_1_19, 36)));
|
||||
empty(id("minecraft:int_range", mapSet(MINECRAFT_1_20_5, 38), mapSet(MINECRAFT_1_20_3, 37), mapSet(MINECRAFT_1_19_3, 36),
|
||||
mapSet(MINECRAFT_1_19, 37)));
|
||||
empty(id("minecraft:float_range", mapSet(MINECRAFT_1_20_5, 39), mapSet(MINECRAFT_1_20_3, 38), mapSet(MINECRAFT_1_19_3, 37),
|
||||
mapSet(MINECRAFT_1_19, 38)));
|
||||
empty(id("minecraft:item_enchantment", mapSet(MINECRAFT_1_19_3, -1), mapSet(MINECRAFT_1_19, 39)));
|
||||
empty(id("minecraft:entity_summon", mapSet(MINECRAFT_1_19_3, -1), mapSet(MINECRAFT_1_19, 40)));
|
||||
empty(id("minecraft:dimension", mapSet(MINECRAFT_1_21_6, 41), mapSet(MINECRAFT_1_20_5, 40), mapSet(MINECRAFT_1_20_3, 39),
|
||||
mapSet(MINECRAFT_1_19_3, 38), mapSet(MINECRAFT_1_19, 41)));
|
||||
empty(id("minecraft:gamemode", mapSet(MINECRAFT_1_21_6, 42), mapSet(MINECRAFT_1_20_5, 41), mapSet(MINECRAFT_1_20_3, 40),
|
||||
mapSet(MINECRAFT_1_19_3, 39))); // 1.19.3
|
||||
empty(id("minecraft:dimension", mapSet(MINECRAFT_1_20_5, 40), mapSet(MINECRAFT_1_20_3, 39), mapSet(MINECRAFT_1_19_3, 38),
|
||||
mapSet(MINECRAFT_1_19, 41)));
|
||||
empty(id("minecraft:gamemode", mapSet(MINECRAFT_1_20_5, 41), mapSet(MINECRAFT_1_20_3, 40), mapSet(MINECRAFT_1_19_3, 39))); // 1.19.3
|
||||
|
||||
empty(id("minecraft:time", mapSet(MINECRAFT_1_21_6, 43), mapSet(MINECRAFT_1_20_5, 42), mapSet(MINECRAFT_1_20_3, 41),
|
||||
mapSet(MINECRAFT_1_19_3, 40), mapSet(MINECRAFT_1_19, 42)), TimeArgumentSerializer.TIME); // added in 1.14
|
||||
empty(id("minecraft:time", mapSet(MINECRAFT_1_20_5, 42), mapSet(MINECRAFT_1_20_3, 41), mapSet(MINECRAFT_1_19_3, 40),
|
||||
mapSet(MINECRAFT_1_19, 42)), TimeArgumentSerializer.TIME); // added in 1.14
|
||||
|
||||
register(id("minecraft:resource_or_tag", mapSet(MINECRAFT_1_21_6, 44), mapSet(MINECRAFT_1_20_5, 43), mapSet(MINECRAFT_1_20_3, 42),
|
||||
mapSet(MINECRAFT_1_19_3, 41), mapSet(MINECRAFT_1_19, 43)), RegistryKeyArgument.class, RegistryKeyArgumentSerializer.REGISTRY);
|
||||
register(id("minecraft:resource_or_tag_key", mapSet(MINECRAFT_1_21_6, 45), mapSet(MINECRAFT_1_20_5, 44), mapSet(MINECRAFT_1_20_3, 43),
|
||||
mapSet(MINECRAFT_1_19_3, 42)),
|
||||
register(id("minecraft:resource_or_tag", mapSet(MINECRAFT_1_20_5, 43), mapSet(MINECRAFT_1_20_3, 42), mapSet(MINECRAFT_1_19_3, 41),
|
||||
mapSet(MINECRAFT_1_19, 43)), RegistryKeyArgument.class, RegistryKeyArgumentSerializer.REGISTRY);
|
||||
register(id("minecraft:resource_or_tag_key", mapSet(MINECRAFT_1_20_5, 44), mapSet(MINECRAFT_1_20_3, 43), mapSet(MINECRAFT_1_19_3, 42)),
|
||||
RegistryKeyArgumentList.ResourceOrTagKey.class,
|
||||
RegistryKeyArgumentList.ResourceOrTagKey.Serializer.REGISTRY);
|
||||
register(id("minecraft:resource", mapSet(MINECRAFT_1_21_6, 46), mapSet(MINECRAFT_1_20_5, 45), mapSet(MINECRAFT_1_20_3, 44),
|
||||
mapSet(MINECRAFT_1_19_3, 43), mapSet(MINECRAFT_1_19, 44)),
|
||||
register(id("minecraft:resource", mapSet(MINECRAFT_1_20_5, 45), mapSet(MINECRAFT_1_20_3, 44), mapSet(MINECRAFT_1_19_3, 43),
|
||||
mapSet(MINECRAFT_1_19, 44)),
|
||||
RegistryKeyArgument.class, RegistryKeyArgumentSerializer.REGISTRY);
|
||||
register(id("minecraft:resource_key", mapSet(MINECRAFT_1_21_6, 47), mapSet(MINECRAFT_1_20_5, 46), mapSet(MINECRAFT_1_20_3, 45),
|
||||
mapSet(MINECRAFT_1_19_3, 44)),
|
||||
register(id("minecraft:resource_key", mapSet(MINECRAFT_1_20_5, 46), mapSet(MINECRAFT_1_20_3, 45), mapSet(MINECRAFT_1_19_3, 44)),
|
||||
RegistryKeyArgumentList.ResourceKey.class,
|
||||
RegistryKeyArgumentList.ResourceKey.Serializer.REGISTRY);
|
||||
register(id("minecraft:resource_selector", mapSet(MINECRAFT_1_21_6, 48), mapSet(MINECRAFT_1_21_5, 47)),
|
||||
register(id("minecraft:resource_selector", mapSet(MINECRAFT_1_21_5, 47)),
|
||||
RegistryKeyArgumentList.ResourceSelector.class,
|
||||
RegistryKeyArgumentList.ResourceSelector.Serializer.REGISTRY);
|
||||
|
||||
empty(id("minecraft:template_mirror", mapSet(MINECRAFT_1_21_6, 49), mapSet(MINECRAFT_1_21_5, 48), mapSet(MINECRAFT_1_20_5, 47),
|
||||
mapSet(MINECRAFT_1_20_3, 46), mapSet(MINECRAFT_1_19, 45))); // 1.19
|
||||
empty(id("minecraft:template_rotation", mapSet(MINECRAFT_1_21_6, 50), mapSet(MINECRAFT_1_21_5, 49), mapSet(MINECRAFT_1_20_5, 48),
|
||||
mapSet(MINECRAFT_1_20_3, 47), mapSet(MINECRAFT_1_19, 46))); // 1.19
|
||||
empty(id("minecraft:heightmap", mapSet(MINECRAFT_1_21_6, 51), mapSet(MINECRAFT_1_21_5, 50), mapSet(MINECRAFT_1_20_3, 49),
|
||||
mapSet(MINECRAFT_1_19_4, 47))); // 1.19.4
|
||||
empty(id("minecraft:template_mirror", mapSet(MINECRAFT_1_21_5, 48), mapSet(MINECRAFT_1_20_5, 47), mapSet(MINECRAFT_1_20_3, 46), mapSet(MINECRAFT_1_19, 45))); // 1.19
|
||||
empty(id("minecraft:template_rotation", mapSet(MINECRAFT_1_21_5, 49), mapSet(MINECRAFT_1_20_5, 48), mapSet(MINECRAFT_1_20_3, 47), mapSet(MINECRAFT_1_19, 46))); // 1.19
|
||||
empty(id("minecraft:heightmap", mapSet(MINECRAFT_1_21_5, 50), mapSet(MINECRAFT_1_20_3, 49), mapSet(MINECRAFT_1_19_4, 47))); // 1.19.4
|
||||
|
||||
empty(id("minecraft:uuid", mapSet(MINECRAFT_1_21_6, 56), mapSet(MINECRAFT_1_21_5, 54),mapSet(MINECRAFT_1_20_5, 53), mapSet(MINECRAFT_1_20_3, 48),
|
||||
mapSet(MINECRAFT_1_19_4, 48), mapSet(MINECRAFT_1_19, 47))); // added in 1.16
|
||||
empty(id("minecraft:uuid", mapSet(MINECRAFT_1_21_5, 54),mapSet(MINECRAFT_1_20_5, 53), mapSet(MINECRAFT_1_20_3, 48), mapSet(MINECRAFT_1_19_4, 48),
|
||||
mapSet(MINECRAFT_1_19, 47))); // added in 1.16
|
||||
|
||||
empty(id("minecraft:loot_table", mapSet(MINECRAFT_1_21_6, 52), mapSet(MINECRAFT_1_21_5, 51), mapSet(MINECRAFT_1_20_5, 50)));
|
||||
empty(id("minecraft:loot_predicate", mapSet(MINECRAFT_1_21_6, 53), mapSet(MINECRAFT_1_21_5, 52), mapSet(MINECRAFT_1_20_5, 51)));
|
||||
empty(id("minecraft:loot_modifier", mapSet(MINECRAFT_1_21_6, 54), mapSet(MINECRAFT_1_21_5, 53), mapSet(MINECRAFT_1_20_5, 52)));
|
||||
|
||||
empty(id("minecraft:hex_color", mapSet(MINECRAFT_1_21_6, 17))); // added in 1.21.6
|
||||
empty(id("minecraft:dialog", mapSet(MINECRAFT_1_21_6, 55))); // added in 1.21.6
|
||||
empty(id("minecraft:loot_table", mapSet(MINECRAFT_1_21_5, 51), mapSet(MINECRAFT_1_20_5, 50)));
|
||||
empty(id("minecraft:loot_predicate", mapSet(MINECRAFT_1_21_5, 52), mapSet(MINECRAFT_1_20_5, 51)));
|
||||
empty(id("minecraft:loot_modifier", mapSet(MINECRAFT_1_21_5, 53), mapSet(MINECRAFT_1_20_5, 52)));
|
||||
|
||||
// Crossstitch support
|
||||
register(id("crossstitch:mod_argument", mapSet(MINECRAFT_1_19, -256)), ModArgumentProperty.class, MOD);
|
||||
|
||||
@ -116,6 +116,8 @@ public class KeyedPlayerChatPacket implements MinecraftPacket {
|
||||
ProtocolUtils.readByteArray(buf));
|
||||
}
|
||||
}
|
||||
|
||||
unsigned = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -132,6 +132,7 @@ public class KeyedPlayerCommandPacket implements MinecraftPacket {
|
||||
unsigned = true;
|
||||
}
|
||||
|
||||
unsigned = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -69,6 +69,7 @@ public class SessionPlayerChatPacket implements MinecraftPacket {
|
||||
this.salt = buf.readLong();
|
||||
this.signed = buf.readBoolean();
|
||||
if (this.signed) {
|
||||
this.signed = false;
|
||||
this.signature = readMessageSignature(buf);
|
||||
} else {
|
||||
this.signature = new byte[0];
|
||||
|
||||
@ -46,6 +46,8 @@ public class SessionPlayerCommandPacket implements MinecraftPacket {
|
||||
this.salt = buf.readLong();
|
||||
this.argumentSignatures = new ArgumentSignatures(buf);
|
||||
this.lastSeenMessages = new LastSeenMessages(buf, protocolVersion);
|
||||
|
||||
this.argumentSignatures = new ArgumentSignatures();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -36,7 +36,7 @@ public class KnownPacksPacket implements MinecraftPacket {
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
final int packCount = ProtocolUtils.readVarInt(buf);
|
||||
if (direction == ProtocolUtils.Direction.SERVERBOUND && packCount > MAX_LENGTH_PACKS) {
|
||||
if (packCount > MAX_LENGTH_PACKS) {
|
||||
throw TOO_MANY_PACKS;
|
||||
}
|
||||
|
||||
|
||||
@ -114,7 +114,7 @@ public class VelocityRegisteredServer implements RegisteredServer, ForwardingAud
|
||||
server.createBootstrap(loop).handler(new ChannelInitializer<>() {
|
||||
@Override
|
||||
protected void initChannel(Channel ch) {
|
||||
ch.pipeline().addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder(ProtocolUtils.Direction.CLIENTBOUND))
|
||||
ch.pipeline().addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder())
|
||||
.addLast(READ_TIMEOUT, new ReadTimeoutHandler(
|
||||
pingOptions.getTimeout() == 0
|
||||
? server.getConfiguration().getReadTimeout()
|
||||
|
||||
@ -24,6 +24,9 @@ import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.kyori.adventure.text.flattener.ComponentFlattener;
|
||||
import net.kyori.adventure.translation.GlobalTranslator;
|
||||
import net.kyori.adventure.translation.TranslationRegistry;
|
||||
import net.kyori.adventure.translation.Translator;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Velocity Translation Mapper.
|
||||
@ -40,9 +43,25 @@ public enum TranslatableMapper implements BiConsumer<TranslatableComponent, Cons
|
||||
final TranslatableComponent translatableComponent,
|
||||
final Consumer<Component> componentConsumer
|
||||
) {
|
||||
final Locale locale = ClosestLocaleMatcher.INSTANCE.lookupClosest(Locale.getDefault());
|
||||
if (GlobalTranslator.translator().canTranslate(translatableComponent.key(), locale)) {
|
||||
componentConsumer.accept(GlobalTranslator.render(translatableComponent, locale));
|
||||
for (final Translator source : GlobalTranslator.translator().sources()) {
|
||||
if (source instanceof TranslationRegistry registry
|
||||
&& registry.contains(translatableComponent.key())) {
|
||||
componentConsumer.accept(GlobalTranslator.render(translatableComponent,
|
||||
ClosestLocaleMatcher.INSTANCE.lookupClosest(Locale.getDefault())));
|
||||
return;
|
||||
}
|
||||
}
|
||||
final @Nullable String fallback = translatableComponent.fallback();
|
||||
if (fallback == null) {
|
||||
return;
|
||||
}
|
||||
for (final Translator source : GlobalTranslator.translator().sources()) {
|
||||
if (source instanceof TranslationRegistry registry && registry.contains(fallback)) {
|
||||
componentConsumer.accept(
|
||||
GlobalTranslator.render(Component.translatable(fallback),
|
||||
ClosestLocaleMatcher.INSTANCE.lookupClosest(Locale.getDefault())));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
9
steamwarci.yml
Normal file
9
steamwarci.yml
Normal file
@ -0,0 +1,9 @@
|
||||
build:
|
||||
- "./gradlew build -x check -x javadoc --no-daemon"
|
||||
|
||||
|
||||
artifacts:
|
||||
"/jars/Velocity.jar": "proxy/build/libs/velocity-proxy-3.4.0-SNAPSHOT-all.jar"
|
||||
|
||||
release:
|
||||
- "mvn deploy:deploy-file -DgroupId=de.steamwar -DartifactId=velocity -Dversion=RELEASE -Dpackaging=jar -Dfile=/jars/Velocity.jar -Durl=file:///var/www/maven/"
|
||||
Reference in New Issue
Block a user