diff --git a/api/src/ap/java/com/velocitypowered/api/plugin/ap/PluginAnnotationProcessor.java b/api/src/ap/java/com/velocitypowered/api/plugin/ap/PluginAnnotationProcessor.java index b22b448e9..661d3a015 100644 --- a/api/src/ap/java/com/velocitypowered/api/plugin/ap/PluginAnnotationProcessor.java +++ b/api/src/ap/java/com/velocitypowered/api/plugin/ap/PluginAnnotationProcessor.java @@ -2,7 +2,6 @@ package com.velocitypowered.api.plugin.ap; import com.google.gson.Gson; import com.velocitypowered.api.plugin.Plugin; -import com.velocitypowered.api.plugin.PluginDescription; import java.io.BufferedWriter; import java.io.IOException; import java.io.Writer; @@ -66,7 +65,7 @@ public class PluginAnnotationProcessor extends AbstractProcessor { } Plugin plugin = element.getAnnotation(Plugin.class); - if (!PluginDescription.ID_PATTERN.matcher(plugin.id()).matches()) { + if (!SerializedPluginDescription.ID_PATTERN.matcher(plugin.id()).matches()) { environment.getMessager().printMessage(Diagnostic.Kind.ERROR, "Invalid ID for plugin " + qualifiedName + ". IDs must start alphabetically, have alphanumeric characters, and can " diff --git a/api/src/ap/java/com/velocitypowered/api/plugin/ap/SerializedPluginDescription.java b/api/src/ap/java/com/velocitypowered/api/plugin/ap/SerializedPluginDescription.java index 782fe3b7f..5d370f827 100644 --- a/api/src/ap/java/com/velocitypowered/api/plugin/ap/SerializedPluginDescription.java +++ b/api/src/ap/java/com/velocitypowered/api/plugin/ap/SerializedPluginDescription.java @@ -8,11 +8,14 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.regex.Pattern; import java.util.stream.Collectors; import org.checkerframework.checker.nullness.qual.Nullable; public class SerializedPluginDescription { + public static final Pattern ID_PATTERN = Pattern.compile("[a-z][a-z0-9-_]{0,63}"); + // @Nullable is used here to make GSON skip these in the serialized file private final String id; private final @Nullable String name; @@ -26,7 +29,9 @@ public class SerializedPluginDescription { private SerializedPluginDescription(String id, String name, String version, String description, String url, List authors, List dependencies, String main) { - this.id = Preconditions.checkNotNull(id, "id"); + Preconditions.checkNotNull(id, "id"); + Preconditions.checkArgument(ID_PATTERN.matcher(id).matches(), "id is not valid"); + this.id = id; this.name = Strings.emptyToNull(name); this.version = Strings.emptyToNull(version); this.description = Strings.emptyToNull(description); diff --git a/api/src/main/java/com/velocitypowered/api/event/connection/ConnectionHandshakeEvent.java b/api/src/main/java/com/velocitypowered/api/event/connection/ConnectionHandshakeEvent.java index 0a7986bf7..252668bea 100644 --- a/api/src/main/java/com/velocitypowered/api/event/connection/ConnectionHandshakeEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/connection/ConnectionHandshakeEvent.java @@ -4,7 +4,7 @@ import com.google.common.base.Preconditions; import com.velocitypowered.api.proxy.InboundConnection; /** - * This event is fired when a handshake is established between a client and Velocity. + * This event is fired when a handshake is established between a client and the proxy. */ public final class ConnectionHandshakeEvent { diff --git a/api/src/main/java/com/velocitypowered/api/plugin/Plugin.java b/api/src/main/java/com/velocitypowered/api/plugin/Plugin.java index eb7b659d7..2ed9970f7 100644 --- a/api/src/main/java/com/velocitypowered/api/plugin/Plugin.java +++ b/api/src/main/java/com/velocitypowered/api/plugin/Plugin.java @@ -14,7 +14,8 @@ public @interface Plugin { /** * The ID of the plugin. This ID should be unique as to not conflict with other plugins. The - * plugin ID must match the {@link PluginDescription#ID_PATTERN}. + * plugin ID may contain alphanumeric characters, dashes, and underscores, and be a maximum + * of 64 characters long. * * @return the ID for this plugin */ diff --git a/api/src/main/java/com/velocitypowered/api/util/title/TextTitle.java b/api/src/main/java/com/velocitypowered/api/util/title/TextTitle.java index 4d0b1ec59..d0265f4f4 100644 --- a/api/src/main/java/com/velocitypowered/api/util/title/TextTitle.java +++ b/api/src/main/java/com/velocitypowered/api/util/title/TextTitle.java @@ -186,21 +186,23 @@ public final class TextTitle implements Title { return this; } - public Builder stay(int ticks) { + private int checkTicks(int ticks) { Preconditions.checkArgument(ticks >= 0, "ticks value %s is negative", ticks); - this.stay = ticks; + return ticks; + } + + public Builder stay(int ticks) { + this.stay = checkTicks(ticks); return this; } public Builder fadeIn(int ticks) { - Preconditions.checkArgument(ticks >= 0, "ticks value %s is negative", ticks); - this.fadeIn = ticks; + this.fadeIn = checkTicks(ticks); return this; } public Builder fadeOut(int ticks) { - Preconditions.checkArgument(ticks >= 0, "ticks value %s is negative", ticks); - this.fadeOut = ticks; + this.fadeOut = checkTicks(ticks); return this; } diff --git a/native/src/main/java/com/velocitypowered/natives/NativeSetupException.java b/native/src/main/java/com/velocitypowered/natives/NativeSetupException.java new file mode 100644 index 000000000..ff6681635 --- /dev/null +++ b/native/src/main/java/com/velocitypowered/natives/NativeSetupException.java @@ -0,0 +1,24 @@ +package com.velocitypowered.natives; + +public class NativeSetupException extends RuntimeException { + + public NativeSetupException() { + } + + public NativeSetupException(String message) { + super(message); + } + + public NativeSetupException(String message, Throwable cause) { + super(message, cause); + } + + public NativeSetupException(Throwable cause) { + super(cause); + } + + public NativeSetupException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/native/src/main/java/com/velocitypowered/natives/compression/JavaVelocityCompressor.java b/native/src/main/java/com/velocitypowered/natives/compression/JavaVelocityCompressor.java index 015b4adca..5ab78fafa 100644 --- a/native/src/main/java/com/velocitypowered/natives/compression/JavaVelocityCompressor.java +++ b/native/src/main/java/com/velocitypowered/natives/compression/JavaVelocityCompressor.java @@ -1,5 +1,7 @@ package com.velocitypowered.natives.compression; +import static com.velocitypowered.natives.util.NativeConstants.ZLIB_BUFFER_SIZE; + import com.google.common.base.Preconditions; import io.netty.buffer.ByteBuf; import java.util.zip.DataFormatException; diff --git a/native/src/main/java/com/velocitypowered/natives/compression/NativeVelocityCompressor.java b/native/src/main/java/com/velocitypowered/natives/compression/NativeVelocityCompressor.java index 40961693a..a541ea6dd 100644 --- a/native/src/main/java/com/velocitypowered/natives/compression/NativeVelocityCompressor.java +++ b/native/src/main/java/com/velocitypowered/natives/compression/NativeVelocityCompressor.java @@ -1,5 +1,7 @@ package com.velocitypowered.natives.compression; +import static com.velocitypowered.natives.util.NativeConstants.ZLIB_BUFFER_SIZE; + import com.google.common.base.Preconditions; import io.netty.buffer.ByteBuf; import java.util.zip.DataFormatException; diff --git a/native/src/main/java/com/velocitypowered/natives/compression/VelocityCompressor.java b/native/src/main/java/com/velocitypowered/natives/compression/VelocityCompressor.java index fd0bd9f02..ad554c352 100644 --- a/native/src/main/java/com/velocitypowered/natives/compression/VelocityCompressor.java +++ b/native/src/main/java/com/velocitypowered/natives/compression/VelocityCompressor.java @@ -8,12 +8,6 @@ import java.util.zip.DataFormatException; * Provides an interface to inflate and deflate {@link ByteBuf}s using zlib. */ public interface VelocityCompressor extends Disposable { - - /** - * The default preferred output buffer size for zlib. - */ - int ZLIB_BUFFER_SIZE = 8192; - void inflate(ByteBuf source, ByteBuf destination) throws DataFormatException; void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException; diff --git a/native/src/main/java/com/velocitypowered/natives/util/NativeConstants.java b/native/src/main/java/com/velocitypowered/natives/util/NativeConstants.java new file mode 100644 index 000000000..f96656125 --- /dev/null +++ b/native/src/main/java/com/velocitypowered/natives/util/NativeConstants.java @@ -0,0 +1,12 @@ +package com.velocitypowered.natives.util; + +public class NativeConstants { + /** + * The default preferred output buffer size for zlib. + */ + public static final int ZLIB_BUFFER_SIZE = 8192; + + private NativeConstants() { + throw new AssertionError(); + } +} diff --git a/native/src/main/java/com/velocitypowered/natives/util/Natives.java b/native/src/main/java/com/velocitypowered/natives/util/Natives.java index 2a395ad46..c028850df 100644 --- a/native/src/main/java/com/velocitypowered/natives/util/Natives.java +++ b/native/src/main/java/com/velocitypowered/natives/util/Natives.java @@ -1,6 +1,7 @@ package com.velocitypowered.natives.util; import com.google.common.collect.ImmutableList; +import com.velocitypowered.natives.NativeSetupException; import com.velocitypowered.natives.compression.JavaVelocityCompressor; import com.velocitypowered.natives.compression.NativeVelocityCompressor; import com.velocitypowered.natives.compression.VelocityCompressorFactory; @@ -37,7 +38,7 @@ public class Natives { })); System.load(tempFile.toAbsolutePath().toString()); } catch (IOException e) { - throw new RuntimeException(e); + throw new NativeSetupException("Unable to copy natives", e); } }; } @@ -57,12 +58,12 @@ public class Natives { public static final NativeCodeLoader cipher = new NativeCodeLoader<>( ImmutableList.of( - /*new NativeCodeLoader.Variant<>(NativeCodeLoader.MACOS, - copyAndLoadNative("/macosx/velocity-cipher.dylib"), "mbed TLS (macOS)", - NativeVelocityCipher.FACTORY), - new NativeCodeLoader.Variant<>(NativeCodeLoader.LINUX, - copyAndLoadNative("/linux_x64/velocity-cipher.so"), "mbed TLS (Linux amd64)", - NativeVelocityCipher.FACTORY),*/ + /*new NativeCodeLoader.Variant<>(NativeCodeLoader.MACOS, + copyAndLoadNative("/macosx/velocity-cipher.dylib"), "mbed TLS (macOS)", + NativeVelocityCipher.FACTORY), + new NativeCodeLoader.Variant<>(NativeCodeLoader.LINUX, + copyAndLoadNative("/linux_x64/velocity-cipher.so"), "mbed TLS (Linux amd64)", + NativeVelocityCipher.FACTORY),*/ new NativeCodeLoader.Variant<>(NativeCodeLoader.ALWAYS, () -> { }, "Java", JavaVelocityCipher.FACTORY) ) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index 84e96d0a5..1725b91af 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -91,6 +91,15 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { @Override public boolean handle(Chat packet) { + VelocityServerConnection serverConnection = player.getConnectedServer(); + if (serverConnection == null) { + return true; + } + MinecraftConnection smc = serverConnection.getConnection(); + if (smc == null) { + return true; + } + String msg = packet.getMessage(); if (msg.startsWith("/")) { try { @@ -106,14 +115,6 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { return true; } } else { - VelocityServerConnection serverConnection = player.getConnectedServer(); - if (serverConnection == null) { - return true; - } - MinecraftConnection smc = serverConnection.getConnection(); - if (smc == null) { - return true; - } PlayerChatEvent event = new PlayerChatEvent(player, msg); server.getEventManager().fire(event) .thenAcceptAsync(pme -> { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/plugin/loader/JavaPluginLoader.java b/proxy/src/main/java/com/velocitypowered/proxy/plugin/loader/JavaPluginLoader.java index ac75badc3..c67740751 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/plugin/loader/JavaPluginLoader.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/plugin/loader/JavaPluginLoader.java @@ -43,9 +43,8 @@ public class JavaPluginLoader implements PluginLoader { } SerializedPluginDescription pd = serialized.get(); - if (!PluginDescription.ID_PATTERN.matcher(pd.getId()).matches()) { - throw new InvalidPluginException("Plugin ID '" + pd.getId() + "' must match pattern " + - PluginDescription.ID_PATTERN.pattern()); + if (!SerializedPluginDescription.ID_PATTERN.matcher(pd.getId()).matches()) { + throw new InvalidPluginException("Plugin ID '" + pd.getId() + "' is invalid."); } PluginClassLoader loader = new PluginClassLoader( diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/GS4QueryHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/GS4QueryHandler.java index f5252078c..f329b7f31 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/GS4QueryHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/GS4QueryHandler.java @@ -69,6 +69,25 @@ public class GS4QueryHandler extends SimpleChannelInboundHandler this.server = server; } + private QueryResponse createInitialResponse() { + return QueryResponse.builder() + .hostname(ComponentSerializers.PLAIN + .serialize(server.getConfiguration().getMotdComponent())) + .gameVersion(ProtocolConstants.SUPPORTED_GENERIC_VERSION_STRING) + .map(server.getConfiguration().getQueryMap()) + .currentPlayers(server.getPlayerCount()) + .maxPlayers(server.getConfiguration().getShowMaxPlayers()) + .proxyPort(server.getConfiguration().getBind().getPort()) + .proxyHost(server.getConfiguration().getBind().getHostString()) + .players(server.getAllPlayers().stream().map(Player::getUsername) + .collect(Collectors.toList())) + .proxyVersion("Velocity") + .plugins( + server.getConfiguration().shouldQueryShowPlugins() ? getRealPluginInformation() + : Collections.emptyList()) + .build(); + } + @Override protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception { ByteBuf queryMessage = msg.content(); @@ -117,22 +136,7 @@ public class GS4QueryHandler extends SimpleChannelInboundHandler } // Build query response - QueryResponse response = QueryResponse.builder() - .hostname(ComponentSerializers.PLAIN - .serialize(server.getConfiguration().getMotdComponent())) - .gameVersion(ProtocolConstants.SUPPORTED_GENERIC_VERSION_STRING) - .map(server.getConfiguration().getQueryMap()) - .currentPlayers(server.getPlayerCount()) - .maxPlayers(server.getConfiguration().getShowMaxPlayers()) - .proxyPort(server.getConfiguration().getBind().getPort()) - .proxyHost(server.getConfiguration().getBind().getHostString()) - .players(server.getAllPlayers().stream().map(Player::getUsername) - .collect(Collectors.toList())) - .proxyVersion("Velocity") - .plugins( - server.getConfiguration().shouldQueryShowPlugins() ? getRealPluginInformation() - : Collections.emptyList()) - .build(); + QueryResponse response = createInitialResponse(); boolean isBasic = queryMessage.readableBytes() == 0; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PlayerListItem.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PlayerListItem.java index c2a5afeb9..a389ed085 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PlayerListItem.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PlayerListItem.java @@ -50,14 +50,13 @@ public class PlayerListItem implements MinecraftPacket { Item item = new Item(ProtocolUtils.readUuid(buf)); items.add(item); switch (action) { - case ADD_PLAYER: { + case ADD_PLAYER: item.setName(ProtocolUtils.readString(buf)); item.setProperties(ProtocolUtils.readProperties(buf)); item.setGameMode(ProtocolUtils.readVarInt(buf)); item.setLatency(ProtocolUtils.readVarInt(buf)); item.setDisplayName(readOptionalComponent(buf)); break; - } case UPDATE_GAMEMODE: item.setGameMode(ProtocolUtils.readVarInt(buf)); break;