Compare commits

..

26 Commits

Author SHA1 Message Date
b6e05cb0b9 Refactor TCP Fast Open checks and update message identifiers.
All checks were successful
SteamWarCI Build successful
Removed transport type conditions for TCP Fast Open to streamline configuration usage. Added imports for new message identifiers in `ClientPlaySessionHandler`. Cleaned up Netty library definitions in `libs.versions.toml`.
2025-04-27 20:09:05 +02:00
1507b91463 Merge remote-tracking branch 'upstream/dev/3.0.0' into update
# Conflicts:
#	proxy/src/main/java/com/velocitypowered/proxy/network/TransportType.java
2025-04-27 19:53:15 +02:00
b06af3718c Merge remote-tracking branch 'github/dev/3.0.0'
All checks were successful
SteamWarCI Build successful
# Conflicts:
#	proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionPlayerCommandPacket.java
2025-04-01 07:06:14 +02:00
a20a896582 Skip javadoc generation
All checks were successful
SteamWarCI Build successful
2025-01-22 09:37:30 +01:00
e1a3421212 Adapt to new server
Some checks failed
SteamWarCI Build failed
2025-01-22 09:33:59 +01:00
19e51a2b12 Merge remote-tracking branch 'upstream/dev/3.0.0' 2024-12-06 11:14:27 +01:00
b89a5c5ce9 Fix CI 2024-12-02 12:45:04 +01:00
65d3277319 Merge remote-tracking branch 'upstream/dev/3.0.0' 2024-11-30 09:25:25 +01:00
a22bfa10f9 Merge pull request 'Update 1.21.2 client support' (#5) from upstream into master
Reviewed-on: https://steamwar.de/devlabs/SteamWar/Velocity/pulls/5
2024-11-11 08:15:32 +01:00
d9d1319a3a Merge remote-tracking branch 'upstream/dev/3.0.0' into upstream
# Conflicts:
#	proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java
2024-11-10 18:32:48 +01:00
15ecbf4345 Merge pull request 'Update Velocity (might fix Command problems) and fix PluginMessages...' (#4) from fix-pluginmessages into master
Reviewed-on: https://steamwar.de/devlabs/SteamWar/Velocity/pulls/4
Reviewed-by: YoyoNow <jwsteam@nidido.de>
2024-08-20 08:14:11 +02:00
5e3bbcd427 Fix command signature issues. 2024-08-20 08:03:18 +02:00
a6c79db07b Remove filter checks to receive PluginMessages unfiltered. 2024-08-18 15:32:08 +02:00
6e33bc6c17 Merge remote-tracking branch 'refs/remotes/upstream/dev/3.0.0' 2024-08-18 15:28:10 +02:00
01208bb359 Indicate NoChatReports support in ServerPing 2024-06-24 18:36:32 +02:00
fa88aaae52 Always unsign chat. 2024-06-21 12:48:58 +02:00
2da400a267 Merge pull request 'Implement Velocity PRs #998 #1246 and #1309 (io_uring, tcp_fastopen and PluginMessage race condition fix)' (#3) from io_uring into master
Reviewed-on: https://steamwar.de/devlabs/SteamWar/Velocity/pulls/3
Reviewed-by: YoyoNow <jwsteam@nidido.de>
2024-06-19 12:06:10 +02:00
8103135dfb Fix type 2024-06-19 10:21:36 +02:00
cfabff7288 Implement Velocity PRs #998 #1246 and #1309 (io_uring, tcp_fastopen and PluginMessage race condition fix) 2024-06-19 10:11:32 +02:00
2f5a27a708 Fix CI 2024-06-19 09:47:18 +02:00
fdfe8bcc4b Fix CI 2024-06-19 09:40:58 +02:00
a19fd8db74 Add UpdateTeamsPacket 2024-06-16 21:27:13 +02:00
e63d71423d Add UpdateTeamsPacket 2024-06-16 21:24:06 +02:00
a7afe35fab Rebuild 2024-06-16 13:25:07 +02:00
56d6339313 Fix JVM 2024-06-16 13:18:29 +02:00
2475572573 Add steamwarci.yml 2024-06-16 12:52:43 +02:00
34 changed files with 437 additions and 391 deletions

View File

@ -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.

View File

@ -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;

View File

@ -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) {

View File

@ -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"

View File

@ -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)

View File

@ -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")) {

View File

@ -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 -> {

View File

@ -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");

View File

@ -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);

View File

@ -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(

View File

@ -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(() -> {

View File

@ -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;

View File

@ -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;
});
}
}
}

View File

@ -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();

View File

@ -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))

View File

@ -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))

View File

@ -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;
}

View File

@ -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;

View File

@ -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 {

View File

@ -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;

View File

@ -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) {

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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);

View File

@ -116,6 +116,8 @@ public class KeyedPlayerChatPacket implements MinecraftPacket {
ProtocolUtils.readByteArray(buf));
}
}
unsigned = true;
}
@Override

View File

@ -132,6 +132,7 @@ public class KeyedPlayerCommandPacket implements MinecraftPacket {
unsigned = true;
}
unsigned = true;
}
@Override

View File

@ -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];

View File

@ -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

View File

@ -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;
}

View File

@ -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()

View File

@ -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
View 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/"