Switch over to Error Prone (now with NullAway!)

There is one major change: we now have a separate artifact for the annotation processor.

As for NullAway, we are currently exempting the clientbound join game/respawn packets. They are ugly and need to be refactored.
This commit is contained in:
Andrew Steinborn
2021-05-13 04:13:15 -04:00
parent c496d912ea
commit 3c41211163
79 changed files with 494 additions and 401 deletions

View File

@@ -7,6 +7,7 @@ plugins {
apply plugin: 'org.cadixdev.licenser'
apply from: '../gradle/checkstyle.gradle'
apply from: '../gradle/errorprone.gradle'
apply plugin: 'com.github.johnrengelman.shadow'
license {
@@ -50,9 +51,8 @@ tasks.withType(Checkstyle) {
}
dependencies {
// Note: we depend on the API twice, first the main sourceset, and then the annotation processor.
implementation project(':velocity-api')
implementation project(':velocity-api').sourceSets.ap.output
implementation project(':velocity-annotation-processor')
implementation project(':velocity-native')
implementation "io.netty:netty-codec:${nettyVersion}"

View File

@@ -17,6 +17,8 @@
package com.velocitypowered.proxy;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.velocitypowered.proxy.config.VelocityConfiguration;
import java.io.File;
import java.io.IOException;
@@ -25,6 +27,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bstats.MetricsBase;
@@ -37,7 +40,7 @@ import org.bstats.json.JsonObjectBuilder;
public class Metrics {
private MetricsBase metricsBase;
private @Nullable MetricsBase metricsBase;
private Metrics(Logger logger, int serviceId, boolean defaultEnabled) {
File configFile = Paths.get("plugins").resolve("bStats").resolve("config.txt").toFile();
@@ -85,7 +88,9 @@ public class Metrics {
* @param chart The chart to add.
*/
public void addCustomChart(CustomChart chart) {
metricsBase.addCustomChart(chart);
if (metricsBase != null) {
metricsBase.addCustomChart(chart);
}
}
private void appendPlatformData(JsonObjectBuilder builder) {
@@ -126,7 +131,7 @@ public class Metrics {
// java.version system property to return $major[.$minor][.$security][-ea], as opposed to
// 1.$major.0_$identifier we can handle pre-9 by checking if the "major" is equal to "1",
// otherwise, 9+
String majorVersion = javaVersion.split("\\.")[0];
String majorVersion = Iterables.get(Splitter.on('.').split(javaVersion), 0);
String release;
int indexOf = javaVersion.lastIndexOf('.');

View File

@@ -90,6 +90,7 @@ import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.IntFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.audience.ForwardingAudience;
import net.kyori.adventure.key.Key;
@@ -193,8 +194,7 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
cm.getBossGroup().terminationFuture().syncUninterruptibly();
}
@EnsuresNonNull({"serverKeyPair", "servers", "pluginManager", "eventManager", "scheduler",
"console", "cm", "configuration"})
@EnsuresNonNull({"serverKeyPair", "eventManager", "console", "cm", "configuration"})
void start() {
logger.info("Booting up {} {}...", version().getName(), version().getVersion());
console.setupStreams();
@@ -252,8 +252,8 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
FileSystemUtils.visitResources(VelocityServer.class, path -> {
logger.info("Loading localizations...");
try {
Files.walk(path).forEach(file -> {
try (Stream<Path> stream = Files.walk(path)) {
stream.forEach(file -> {
if (!Files.isRegularFile(file)) {
return;
}
@@ -396,12 +396,18 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
RegisteredServer next = player.getNextServerToTry();
if (next != null) {
player.createConnectionRequest(next).connectWithIndication()
.whenComplete((success, ex) -> {
if (ex != null || success == null || !success) {
.thenAccept((success) -> {
if (success == null || !success) {
player.disconnect(Component.text("Your server has been changed, but we could "
+ "not move you to any fallback servers."));
}
latch.countDown();
})
.exceptionally(throwable -> {
player.disconnect(Component.text("Your server has been changed, but we could "
+ "not move you to any fallback servers."));
latch.countDown();
return null;
});
} else {
latch.countDown();
@@ -426,8 +432,8 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
}
if (configuration.isQueryEnabled() && (!newConfiguration.isQueryEnabled()
|| newConfiguration.getQueryPort() != configuration.getQueryPort()
&& oldBind instanceof InetSocketAddress)) {
|| ((newConfiguration.getQueryPort() != configuration.getQueryPort())
&& (oldBind instanceof InetSocketAddress)))) {
this.cm.close(new InetSocketAddress(
((InetSocketAddress) oldBind).getHostString(), configuration.getQueryPort()));
}
@@ -444,7 +450,7 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
}
/**
* Shuts down the proxy, kicking players with the specified {@param reason}.
* Shuts down the proxy, kicking players with the specified {@code reason}.
*
* @param explicitExit whether the user explicitly shut down the proxy
* @param reason message to kick online players with

View File

@@ -38,6 +38,7 @@ import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.TranslatableComponent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.Style;
public class GlistCommand {
@@ -122,7 +123,7 @@ public class GlistCommand {
NamedTextColor.DARK_AQUA))
.append(Component.text("(" + onServer.size() + ")", NamedTextColor.GRAY))
.append(Component.text(": "))
.resetStyle();
.style(Style.empty());
for (int i = 0; i < onServer.size(); i++) {
Player player = onServer.get(i);

View File

@@ -592,18 +592,10 @@ public class VelocityConfiguration implements ProxyConfig {
}
}
private ForcedHosts(Map<String, List<String>> forcedHosts) {
this.forcedHosts = forcedHosts;
}
private Map<String, List<String>> getForcedHosts() {
return forcedHosts;
}
private void setForcedHosts(Map<String, List<String>> forcedHosts) {
this.forcedHosts = forcedHosts;
}
@Override
public String toString() {
return "ForcedHosts{"

View File

@@ -94,6 +94,7 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
this.remoteAddress = channel.remoteAddress();
this.server = server;
this.state = ProtocolStates.HANDSHAKE;
this.protocolVersion = ProtocolVersion.UNKNOWN;
}
@Override

View File

@@ -51,6 +51,7 @@ import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.handler.timeout.ReadTimeoutException;
import java.util.Collection;
import javax.annotation.Nullable;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -204,10 +205,8 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
RootCommandNode<CommandSource> rootNode = commands.getRootNode();
if (server.configuration().isAnnounceProxyCommands()) {
// Inject commands from the proxy.
RootCommandNode<CommandSource> dispatcherRootNode =
(RootCommandNode<CommandSource>)
filterNode(server.commandManager().getDispatcher().getRoot());
assert dispatcherRootNode != null : "Filtering root node returned null.";
RootCommandNode<CommandSource> dispatcherRootNode = filterRootNode(server.commandManager()
.getDispatcher().getRoot());
Collection<CommandNode<CommandSource>> proxyNodes = dispatcherRootNode.getChildren();
for (CommandNode<CommandSource> node : proxyNodes) {
CommandNode<CommandSource> existingServerChild = rootNode.getChild(node.getName());
@@ -228,6 +227,27 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
return true;
}
/**
* Creates a deep copy of the provided command node, but removes any node that are not accessible
* by the player (respecting the requirement of the node). This function is specialized for
* root command nodes, so as to get better safety guarantees.
*
* @param source source node
* @return filtered node
*/
private RootCommandNode<CommandSource> filterRootNode(CommandNode<CommandSource> source) {
RootCommandNode<CommandSource> dest = new RootCommandNode<>();
for (CommandNode<CommandSource> sourceChild : source.getChildren()) {
CommandNode<CommandSource> destChild = filterNode(sourceChild);
if (destChild == null) {
continue;
}
dest.addChild(destChild);
}
return dest;
}
/**
* Creates a deep copy of the provided command node, but removes any node that are not accessible
* by the player (respecting the requirement of the node).
@@ -235,32 +255,27 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
* @param source source node
* @return filtered node
*/
private CommandNode<CommandSource> filterNode(CommandNode<CommandSource> source) {
CommandNode<CommandSource> dest;
if (source instanceof RootCommandNode) {
dest = new RootCommandNode<>();
} else {
if (source.getRequirement() != null) {
try {
if (!source.getRequirement().test(serverConn.player())) {
return null;
}
} catch (Throwable e) {
// swallow everything because plugins
logger.error(
"Requirement test for command node " + source + " encountered an exception", e);
private @Nullable CommandNode<CommandSource> filterNode(CommandNode<CommandSource> source) {
if (source.getRequirement() != null) {
try {
if (!source.getRequirement().test(serverConn.player())) {
return null;
}
} catch (Throwable e) {
// swallow everything because plugins
logger.error(
"Requirement test for command node " + source + " encountered an exception", e);
}
ArgumentBuilder<CommandSource, ?> destChildBuilder = source.createBuilder();
destChildBuilder.requires((commandSource) -> true);
if (destChildBuilder.getRedirect() != null) {
destChildBuilder.redirect(filterNode(destChildBuilder.getRedirect()));
}
dest = destChildBuilder.build();
}
ArgumentBuilder<CommandSource, ?> destChildBuilder = source.createBuilder();
destChildBuilder.requires((commandSource) -> true);
if (destChildBuilder.getRedirect() != null) {
destChildBuilder.redirect(filterNode(destChildBuilder.getRedirect()));
}
CommandNode<CommandSource> dest = destChildBuilder.build();
for (CommandNode<CommandSource> sourceChild : source.getChildren()) {
CommandNode<CommandSource> destChild = filterNode(sourceChild);
if (destChild == null) {

View File

@@ -85,21 +85,12 @@ public class BungeeCordMessageResponder {
}
}
private void processIp(ByteBufDataInput in) {
private void processIp() {
ByteBuf buf = Unpooled.buffer();
ByteBufDataOutput out = new ByteBufDataOutput(buf);
out.writeUTF("IP");
SocketAddress address = player.remoteAddress();
if (address instanceof InetSocketAddress) {
InetSocketAddress serverInetAddr = (InetSocketAddress) address;
out.writeUTF(serverInetAddr.getHostString());
out.writeInt(serverInetAddr.getPort());
} else {
out.writeUTF("unix://" + ((DomainSocketAddress) address).path());
out.writeInt(0);
}
sendResponseOnConnection(buf);
sendIpOutput(player, buf, out);
}
private void processPlayerCount(ByteBufDataInput in) {
@@ -243,20 +234,24 @@ public class BungeeCordMessageResponder {
out.writeUTF("IPOther");
out.writeUTF(player.username());
SocketAddress address = player.remoteAddress();
if (address instanceof InetSocketAddress) {
InetSocketAddress serverInetAddr = (InetSocketAddress) address;
out.writeUTF(serverInetAddr.getHostString());
out.writeInt(serverInetAddr.getPort());
} else {
out.writeUTF("unix://" + ((DomainSocketAddress) address).path());
out.writeInt(0);
}
sendResponseOnConnection(buf);
sendIpOutput(player, buf, out);
}
}
private void sendIpOutput(Player player, ByteBuf buf, ByteBufDataOutput out) {
SocketAddress address = player.remoteAddress();
if (address instanceof InetSocketAddress) {
InetSocketAddress serverInetAddr = (InetSocketAddress) address;
out.writeUTF(serverInetAddr.getHostString());
out.writeInt(serverInetAddr.getPort());
} else {
out.writeUTF("127.0.0.1");
out.writeInt(0);
}
sendResponseOnConnection(buf);
}
private void processServerIp(ByteBufDataInput in) {
RegisteredServer info = proxy.server(in.readUTF());
if (info != null) {
@@ -360,7 +355,7 @@ public class BungeeCordMessageResponder {
this.processConnectOther(in);
break;
case "IP":
this.processIp(in);
this.processIp();
break;
case "PlayerCount":
this.processPlayerCount(in);

View File

@@ -46,6 +46,7 @@ import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import net.kyori.adventure.text.Component;
import org.checkerframework.checker.nullness.qual.Nullable;
public class LoginSessionHandler implements MinecraftSessionHandler {
@@ -147,7 +148,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
}
}
private static String cleanRemoteAddress(SocketAddress address) {
private static String cleanRemoteAddress(@Nullable SocketAddress address) {
if (address instanceof InetSocketAddress) {
String addressString = ((InetSocketAddress) address).getAddress().getHostAddress();
int ipv6ScopeIdx = addressString.indexOf('%');

View File

@@ -231,7 +231,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
}
@Override
public SocketAddress remoteAddress() {
public @Nullable SocketAddress remoteAddress() {
return connection.getRemoteAddress();
}
@@ -272,7 +272,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
type == MessageType.CHAT
? ClientboundChatPacket.CHAT_TYPE
: ClientboundChatPacket.SYSTEM_TYPE,
identity.uuid()
identity
));
}
@@ -296,7 +296,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
connection.write(new ClientboundChatPacket(
object.toString(),
ClientboundChatPacket.GAME_INFO_TYPE,
Identity.nil().uuid()
Identity.nil()
));
}
}
@@ -564,8 +564,14 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
case CONNECTION_IN_PROGRESS:
// Fatal case
case CONNECTION_CANCELLED:
disconnect(status.failureReason() != null ? status.failureReason()
: res.message());
Component disconnectReason = status.failureReason();
if (disconnectReason == null) {
disconnectReason = res.message();
if (disconnectReason == null) {
disconnectReason = ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR;
}
}
disconnect(disconnectReason);
break;
case SERVER_DISCONNECTED:
Component reason = status.failureReason() != null ? status.failureReason()
@@ -595,7 +601,12 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
// In case someone gets creative, assume we want to disconnect the player.
disconnect(friendlyReason);
}
}, connection.eventLoop());
}, connection.eventLoop())
.exceptionally(throwable -> {
logger.error("Unable to handle server disconnection for {}", this, throwable);
disconnect(friendlyReason);
return null;
});
}
/**
@@ -689,7 +700,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
Player connectedPlayer = server.player(this.id());
server.unregisterConnection(this);
DisconnectEventImpl.LoginStatus status;
LoginStatus status;
if (connectedPlayer != null) {
if (connectedPlayer.connectedServer() != null) {
status = LoginStatus.PRE_SERVER_JOIN;

View File

@@ -39,6 +39,7 @@ import com.velocitypowered.proxy.network.registry.state.ProtocolStates;
import io.netty.buffer.ByteBuf;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Objects;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
@@ -140,8 +141,9 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
return;
}
if (!event.result().isAllowed()) {
ic.disconnectQuietly(event.result().reason());
@Nullable Component disconnectReason = event.result().reason();
if (disconnectReason != null) {
ic.disconnectQuietly(disconnectReason);
} else {
// if the handshake is changed, propagate the change
if (!event.currentHostname().equals(event.originalHostname())) {
@@ -232,8 +234,8 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
}
@Override
public InetSocketAddress remoteAddress() {
return (InetSocketAddress) connection.getRemoteAddress();
public @Nullable SocketAddress remoteAddress() {
return connection.getRemoteAddress();
}
@Override

View File

@@ -51,12 +51,12 @@ public final class InitialInboundConnection implements InboundConnection,
}
@Override
public SocketAddress remoteAddress() {
public @Nullable SocketAddress remoteAddress() {
return connection.getRemoteAddress();
}
@Override
public @Nullable InetSocketAddress connectedHostname() {
public InetSocketAddress connectedHostname() {
return InetSocketAddress.createUnresolved(cleanedHostname, handshake.getPort());
}

View File

@@ -228,9 +228,4 @@ public class StatusSessionHandler implements MinecraftSessionHandler {
// what even is going on?
connection.close(true);
}
private enum State {
AWAITING_REQUEST,
RECEIVED_REQUEST
}
}

View File

@@ -191,7 +191,7 @@ public enum LegacyForgeHandshakeClientPhase implements ClientConnectionPhase {
* {@link #nextPhase()}. A null indicates there is no
* further phase to transition to.
*/
LegacyForgeHandshakeClientPhase(Integer packetToAdvanceOn) {
LegacyForgeHandshakeClientPhase(@Nullable Integer packetToAdvanceOn) {
this.packetToAdvanceOn = packetToAdvanceOn;
}

View File

@@ -23,7 +23,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
public final class DimensionInfo {
private final String registryIdentifier;
private final String levelName;
private final @Nullable String levelName;
private final boolean isFlat;
private final boolean isDebugType;
@@ -60,4 +60,14 @@ public final class DimensionInfo {
public String getRegistryIdentifier() {
return registryIdentifier;
}
@Override
public String toString() {
return "DimensionInfo{"
+ "registryIdentifier='" + registryIdentifier + '\''
+ ", levelName='" + levelName + '\''
+ ", isFlat=" + isFlat
+ ", isDebugType=" + isDebugType
+ '}';
}
}

View File

@@ -118,4 +118,9 @@ public final class DimensionRegistry {
}
return mappings.build();
}
@Override
public String toString() {
return levelNames.toString();
}
}

View File

@@ -18,15 +18,16 @@
package com.velocitypowered.proxy.event;
import com.velocitypowered.api.event.EventTask;
import org.checkerframework.checker.nullness.qual.Nullable;
public interface UntargetedEventHandler {
EventTask execute(Object targetInstance, Object event);
@Nullable EventTask execute(Object targetInstance, Object event);
interface Void extends UntargetedEventHandler {
interface VoidHandler extends UntargetedEventHandler {
@Override
default EventTask execute(final Object targetInstance, final Object event) {
default @Nullable EventTask execute(final Object targetInstance, final Object event) {
executeVoid(targetInstance, event);
return null;
}

View File

@@ -21,6 +21,7 @@ import static java.util.Objects.requireNonNull;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.base.VerifyException;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.reflect.TypeToken;
@@ -32,6 +33,7 @@ import com.velocitypowered.api.event.EventTask;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.plugin.PluginContainer;
import com.velocitypowered.api.plugin.PluginManager;
import com.velocitypowered.proxy.event.UntargetedEventHandler.VoidHandler;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Method;
@@ -67,8 +69,8 @@ public class VelocityEventManager implements EventManager {
private static final MethodHandles.Lookup methodHandlesLookup = MethodHandles.lookup();
private static final LambdaType<UntargetedEventHandler> untargetedHandlerType =
LambdaType.of(UntargetedEventHandler.class);
private static final LambdaType<UntargetedEventHandler.Void> untargetedVoidHandlerType =
LambdaType.of(UntargetedEventHandler.Void.class);
private static final LambdaType<VoidHandler> untargetedVoidHandlerType =
LambdaType.of(VoidHandler.class);
private static final Comparator<HandlerRegistration> handlerComparator =
Comparator.comparingInt(o -> o.order);
@@ -77,7 +79,7 @@ public class VelocityEventManager implements EventManager {
private final PluginManager pluginManager;
private final Multimap<Class<?>, HandlerRegistration> handlersByType = HashMultimap.create();
private final LoadingCache<Class<?>, @Nullable HandlersCache> handlersCache =
private final LoadingCache<Class<?>, HandlersCache> handlersCache =
Caffeine.newBuilder().build(this::bakeHandlers);
private final LoadingCache<Method, UntargetedEventHandler> untargetedMethodHandlers =
@@ -341,9 +343,12 @@ public class VelocityEventManager implements EventManager {
info.method.getName(), info.method.getDeclaringClass().getName(), info.errors);
continue;
}
final UntargetedEventHandler untargetedHandler =
untargetedMethodHandlers.get(info.method);
final UntargetedEventHandler untargetedHandler = untargetedMethodHandlers.get(info.method);
assert untargetedHandler != null;
if (info.eventType == null) {
throw new VerifyException("Event type is not present and there are no errors");
}
final EventHandler<Object> handler = event -> untargetedHandler.execute(listener, event);
registrations.add(new HandlerRegistration(pluginContainer, info.order,
info.eventType, listener, handler, info.asyncType));
@@ -456,7 +461,12 @@ public class VelocityEventManager implements EventManager {
private final boolean currentlyAsync;
private final E event;
// This field is modified via a VarHandle, so this field is used and cannot be final.
@SuppressWarnings({"UnusedVariable", "FieldMayBeFinal"})
private volatile int state = TASK_STATE_DEFAULT;
// This field is modified via a VarHandle, so this field is used and cannot be final.
@SuppressWarnings({"UnusedVariable", "FieldMayBeFinal"})
private volatile boolean resumed = false;
private ContinuationTask(

View File

@@ -95,7 +95,7 @@ public enum ProtocolUtils {
int maxRead = Math.min(5, buf.readableBytes());
for (int j = 0; j < maxRead; j++) {
int k = buf.readByte();
i |= (k & 0x7F) << j * 7;
i |= (k & 0x7F) << (j * 7);
if ((k & 0x80) != 128) {
return i;
}
@@ -123,7 +123,7 @@ public enum ProtocolUtils {
if ((value & (0xFFFFFFFF << 7)) == 0) {
buf.writeByte(value);
} else if ((value & (0xFFFFFFFF << 14)) == 0) {
int w = (value & 0x7F | 0x80) << 8 | (value >>> 7);
int w = ((value & 0x7F) | 0x80) << 8 | (value >>> 7);
buf.writeShort(w);
} else {
writeVarIntFull(buf, value);
@@ -135,18 +135,19 @@ public enum ProtocolUtils {
if ((value & (0xFFFFFFFF << 7)) == 0) {
buf.writeByte(value);
} else if ((value & (0xFFFFFFFF << 14)) == 0) {
int w = (value & 0x7F | 0x80) << 8 | (value >>> 7);
int w = (((value & 0x7F) | 0x80) << 8) | (value >>> 7);
buf.writeShort(w);
} else if ((value & (0xFFFFFFFF << 21)) == 0) {
int w = (value & 0x7F | 0x80) << 16 | ((value >>> 7) & 0x7F | 0x80) << 8 | (value >>> 14);
int w =
(((value & 0x7F) | 0x80) << 16) | ((((value >>> 7) & 0x7F) | 0x80) << 8) | (value >>> 14);
buf.writeMedium(w);
} else if ((value & (0xFFFFFFFF << 28)) == 0) {
int w = (value & 0x7F | 0x80) << 24 | (((value >>> 7) & 0x7F | 0x80) << 16)
| ((value >>> 14) & 0x7F | 0x80) << 8 | (value >>> 21);
int w = (((value & 0x7F) | 0x80) << 24) | ((((value >>> 7) & 0x7F) | 0x80) << 16)
| ((((value >>> 14) & 0x7F) | 0x80) << 8) | (value >>> 21);
buf.writeInt(w);
} else {
int w = (value & 0x7F | 0x80) << 24 | ((value >>> 7) & 0x7F | 0x80) << 16
| ((value >>> 14) & 0x7F | 0x80) << 8 | ((value >>> 21) & 0x7F | 0x80);
int w = (((value & 0x7F) | 0x80) << 24) | ((((value >>> 7) & 0x7F) | 0x80) << 16)
| ((((value >>> 14) & 0x7F) | 0x80) << 8) | (((value >>> 21) & 0x7F) | 0x80);
buf.writeInt(w);
buf.writeByte(value >>> 28);
}
@@ -160,7 +161,8 @@ public enum ProtocolUtils {
*/
public static void write21BitVarInt(ByteBuf buf, int value) {
// See https://steinborn.me/posts/performance/how-fast-can-you-write-a-varint/
int w = (value & 0x7F | 0x80) << 16 | ((value >>> 7) & 0x7F | 0x80) << 8 | (value >>> 14);
int w =
(((value & 0x7F) | 0x80) << 16) | ((((value >>> 7) & 0x7F) | 0x80) << 8) | (value >>> 14);
buf.writeMedium(w);
}

View File

@@ -42,6 +42,7 @@ import io.netty.channel.unix.ServerDomainSocketChannel;
import java.net.SocketAddress;
import java.util.concurrent.ThreadFactory;
import java.util.function.BiFunction;
import org.checkerframework.checker.nullness.qual.Nullable;
enum TransportType {
NIO("NIO", NioServerSocketChannel::new,
@@ -61,16 +62,16 @@ enum TransportType {
final ChannelFactory<? extends ServerSocketChannel> serverSocketChannelFactory;
final ChannelFactory<? extends SocketChannel> socketChannelFactory;
final ChannelFactory<? extends DatagramChannel> datagramChannelFactory;
final ChannelFactory<? extends ServerDomainSocketChannel> domainServerSocketChannelFactory;
final ChannelFactory<? extends DomainSocketChannel> domainSocketChannelFactory;
final @Nullable ChannelFactory<? extends ServerDomainSocketChannel> domainServerSocketChannelFactory;
final @Nullable ChannelFactory<? extends DomainSocketChannel> domainSocketChannelFactory;
final BiFunction<String, Type, EventLoopGroup> eventLoopGroupFactory;
TransportType(final String name,
final ChannelFactory<? extends ServerSocketChannel> serverSocketChannelFactory,
final ChannelFactory<? extends SocketChannel> socketChannelFactory,
final ChannelFactory<? extends DatagramChannel> datagramChannelFactory,
final ChannelFactory<? extends ServerDomainSocketChannel> domainServerSocketChannelFactory,
final ChannelFactory<? extends DomainSocketChannel> domainSocketChannelFactory,
@Nullable final ChannelFactory<? extends ServerDomainSocketChannel> domainServerSocketChannelFactory,
@Nullable final ChannelFactory<? extends DomainSocketChannel> domainSocketChannelFactory,
final BiFunction<String, Type, EventLoopGroup> eventLoopGroupFactory) {
this.name = name;
this.serverSocketChannelFactory = serverSocketChannelFactory;

View File

@@ -20,6 +20,7 @@ package com.velocitypowered.proxy.network.packet;
import static com.velocitypowered.proxy.network.PluginMessageUtil.transformLegacyToModernChannel;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.network.ProtocolUtils;
import com.velocitypowered.proxy.network.buffer.TypedDefaultByteBufHolder;
@@ -60,18 +61,14 @@ public abstract class AbstractPluginMessagePacket<S extends AbstractPluginMessag
};
}
protected final @Nullable String channel;
protected final String channel;
protected AbstractPluginMessagePacket(String channel,
@MonotonicNonNull ByteBuf backing) {
protected AbstractPluginMessagePacket(String channel, @MonotonicNonNull ByteBuf backing) {
super(backing);
this.channel = channel;
this.channel = Preconditions.checkNotNull(channel, "channel");
}
public String getChannel() {
if (channel == null) {
throw new IllegalStateException("Channel is not specified.");
}
return channel;
}

View File

@@ -23,7 +23,7 @@ import io.netty.buffer.ByteBuf;
public interface Packet {
@Deprecated
default void decode(ByteBuf buf, PacketDirection direction, ProtocolVersion protocolVersion) {
default void decode(ByteBuf buf, ProtocolVersion protocolVersion) {
throw new UnsupportedOperationException();
}

View File

@@ -46,7 +46,7 @@ public interface PacketReader<P extends Packet> {
static <P extends Packet> PacketReader<P> method(final Supplier<P> factory) {
return (buf, version) -> {
final P packet = factory.get();
packet.decode(buf, null, version);
packet.decode(buf, version);
return packet;
};
}

View File

@@ -37,7 +37,6 @@ import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.network.ProtocolUtils;
import com.velocitypowered.proxy.network.packet.Packet;
import com.velocitypowered.proxy.network.packet.PacketDirection;
import com.velocitypowered.proxy.network.packet.PacketHandler;
import com.velocitypowered.proxy.network.packet.PacketReader;
import com.velocitypowered.proxy.network.packet.PacketWriter;
@@ -84,7 +83,7 @@ public class ClientboundAvailableCommandsPacket implements Packet {
}
@Override
public void decode(ByteBuf buf, PacketDirection direction, ProtocolVersion protocolVersion) {
public void decode(ByteBuf buf, ProtocolVersion protocolVersion) {
int commands = ProtocolUtils.readVarInt(buf);
WireNode[] wireNodes = new WireNode[commands];
for (int i = 0; i < commands; i++) {

View File

@@ -21,7 +21,6 @@ import com.google.common.base.MoreObjects;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.network.ProtocolUtils;
import com.velocitypowered.proxy.network.packet.Packet;
import com.velocitypowered.proxy.network.packet.PacketDirection;
import com.velocitypowered.proxy.network.packet.PacketHandler;
import com.velocitypowered.proxy.network.packet.PacketReader;
import com.velocitypowered.proxy.network.packet.PacketWriter;
@@ -109,7 +108,7 @@ public class ClientboundBossBarPacket implements Packet {
}
@Override
public void decode(ByteBuf buf, PacketDirection direction, ProtocolVersion version) {
public void decode(ByteBuf buf, ProtocolVersion version) {
this.uuid = ProtocolUtils.readUuid(buf);
this.action = ProtocolUtils.readVarInt(buf);
switch (action) {

View File

@@ -21,60 +21,40 @@ import com.google.common.base.MoreObjects;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.network.ProtocolUtils;
import com.velocitypowered.proxy.network.packet.Packet;
import com.velocitypowered.proxy.network.packet.PacketDirection;
import com.velocitypowered.proxy.network.packet.PacketHandler;
import com.velocitypowered.proxy.network.packet.PacketReader;
import com.velocitypowered.proxy.network.packet.PacketWriter;
import io.netty.buffer.ByteBuf;
import java.util.UUID;
import net.kyori.adventure.identity.Identity;
import org.checkerframework.checker.nullness.qual.Nullable;
public class ClientboundChatPacket implements Packet {
public static final PacketReader<ClientboundChatPacket> DECODER = PacketReader.method(ClientboundChatPacket::new);
public static final PacketWriter<ClientboundChatPacket> ENCODER = PacketWriter.deprecatedEncode();
public static final PacketReader<ClientboundChatPacket> DECODER = PacketReader.unsupported();
public static final PacketWriter<ClientboundChatPacket> ENCODER = (out, packet, version) -> {
ProtocolUtils.writeString(out, packet.message);
if (version.gte(ProtocolVersion.MINECRAFT_1_8)) {
out.writeByte(packet.type);
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) {
ProtocolUtils.writeUuid(out, packet.sender.uuid());
}
}
};
public static final byte CHAT_TYPE = (byte) 0;
public static final byte SYSTEM_TYPE = (byte) 1;
public static final byte GAME_INFO_TYPE = (byte) 2;
private @Nullable String message;
private String message;
private byte type;
private @Nullable UUID sender;
private Identity sender;
private ClientboundChatPacket() {
}
public ClientboundChatPacket(String message, byte type, UUID sender) {
public ClientboundChatPacket(String message, byte type, Identity sender) {
this.message = message;
this.type = type;
this.sender = sender;
}
@Override
public void decode(ByteBuf buf, PacketDirection direction, ProtocolVersion version) {
message = ProtocolUtils.readString(buf);
if (version.gte(ProtocolVersion.MINECRAFT_1_8)) {
type = buf.readByte();
if (version.gte(ProtocolVersion.MINECRAFT_1_16)) {
sender = ProtocolUtils.readUuid(buf);
}
}
}
@Override
public void encode(ByteBuf buf, ProtocolVersion version) {
if (message == null) {
throw new IllegalStateException("Message is not specified");
}
ProtocolUtils.writeString(buf, message);
if (version.gte(ProtocolVersion.MINECRAFT_1_8)) {
buf.writeByte(type);
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) {
ProtocolUtils.writeUuid(buf, sender);
}
}
}
@Override
public boolean handle(PacketHandler handler) {
return handler.handle(this);
@@ -91,10 +71,6 @@ public class ClientboundChatPacket implements Packet {
return type;
}
public UUID getSenderUuid() {
return sender;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)

View File

@@ -23,7 +23,6 @@ import com.google.common.base.MoreObjects;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.network.ProtocolUtils;
import com.velocitypowered.proxy.network.packet.Packet;
import com.velocitypowered.proxy.network.packet.PacketDirection;
import com.velocitypowered.proxy.network.packet.PacketHandler;
import com.velocitypowered.proxy.network.packet.PacketReader;
import com.velocitypowered.proxy.network.packet.PacketWriter;
@@ -54,7 +53,7 @@ public class ClientboundEncryptionRequestPacket implements Packet {
}
@Override
public void decode(ByteBuf buf, PacketDirection direction, ProtocolVersion version) {
public void decode(ByteBuf buf, ProtocolVersion version) {
this.serverId = ProtocolUtils.readString(buf, 20);
if (version.gte(ProtocolVersion.MINECRAFT_1_8)) {

View File

@@ -24,7 +24,6 @@ import com.velocitypowered.proxy.connection.registry.DimensionInfo;
import com.velocitypowered.proxy.connection.registry.DimensionRegistry;
import com.velocitypowered.proxy.network.ProtocolUtils;
import com.velocitypowered.proxy.network.packet.Packet;
import com.velocitypowered.proxy.network.packet.PacketDirection;
import com.velocitypowered.proxy.network.packet.PacketHandler;
import com.velocitypowered.proxy.network.packet.PacketReader;
import com.velocitypowered.proxy.network.packet.PacketWriter;
@@ -35,6 +34,9 @@ import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.ListBinaryTag;
import org.checkerframework.checker.nullness.qual.Nullable;
// TODO: This class is in dire need of a refactor. Suppressing the warning is only done as an
// implicit acknowledgement that this code is very bad.
@SuppressWarnings("WarnAway")
public class ClientboundJoinGamePacket implements Packet {
public static final PacketReader<ClientboundJoinGamePacket> DECODER = PacketReader.method(ClientboundJoinGamePacket::new);
public static final PacketWriter<ClientboundJoinGamePacket> ENCODER = PacketWriter.deprecatedEncode();
@@ -188,7 +190,7 @@ public class ClientboundJoinGamePacket implements Packet {
}
@Override
public void decode(ByteBuf buf, PacketDirection direction, ProtocolVersion version) {
public void decode(ByteBuf buf, ProtocolVersion version) {
this.entityId = buf.readInt();
if (version.gte(ProtocolVersion.MINECRAFT_1_16_2)) {
this.isHardcore = buf.readBoolean();
@@ -196,7 +198,7 @@ public class ClientboundJoinGamePacket implements Packet {
} else {
this.gamemode = buf.readByte();
this.isHardcore = (this.gamemode & 0x08) != 0;
this.gamemode &= ~0x08;
this.gamemode &= (short) (this.gamemode & ~0x08);
}
String dimensionIdentifier = null;
String levelName = null;

View File

@@ -84,7 +84,7 @@ public class ClientboundLoginPluginMessagePacket extends DefaultByteBufHolder im
if (this == other) {
return true;
}
if (other == null || this.getClass() != other.getClass()) {
if (!(other instanceof ClientboundLoginPluginMessagePacket)) {
return false;
}
final ClientboundLoginPluginMessagePacket that = (ClientboundLoginPluginMessagePacket) other;

View File

@@ -18,13 +18,13 @@
package com.velocitypowered.proxy.network.packet.clientbound;
import com.google.common.base.MoreObjects;
import com.google.common.base.VerifyException;
import com.google.common.collect.ImmutableList;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.player.TabListEntry;
import com.velocitypowered.api.util.GameProfile;
import com.velocitypowered.proxy.network.ProtocolUtils;
import com.velocitypowered.proxy.network.packet.Packet;
import com.velocitypowered.proxy.network.packet.PacketDirection;
import com.velocitypowered.proxy.network.packet.PacketHandler;
import com.velocitypowered.proxy.network.packet.PacketReader;
import com.velocitypowered.proxy.network.packet.PacketWriter;
@@ -65,7 +65,7 @@ public class ClientboundPlayerListItemPacket implements Packet {
}
@Override
public void decode(ByteBuf buf, PacketDirection direction, ProtocolVersion version) {
public void decode(ByteBuf buf, ProtocolVersion version) {
if (version.gte(ProtocolVersion.MINECRAFT_1_8)) {
action = ProtocolUtils.readVarInt(buf);
int length = ProtocolUtils.readVarInt(buf);
@@ -121,7 +121,9 @@ public class ClientboundPlayerListItemPacket implements Packet {
ProtocolUtils.writeVarInt(buf, items.size());
for (Item item : items) {
UUID uuid = item.getUuid();
assert uuid != null : "UUID-less entry serialization attempt - 1.7 component!";
if (uuid == null) {
throw new VerifyException("UUID-less entry serialization attempt - 1.7 component!");
}
ProtocolUtils.writeUuid(buf, uuid);
switch (action) {
@@ -189,7 +191,7 @@ public class ClientboundPlayerListItemPacket implements Packet {
public static class Item {
private final UUID uuid;
private final @Nullable UUID uuid;
private String name = "";
private List<GameProfile.Property> properties = ImmutableList.of();
private int gameMode;
@@ -200,7 +202,7 @@ public class ClientboundPlayerListItemPacket implements Packet {
uuid = null;
}
public Item(UUID uuid) {
public Item(@Nullable UUID uuid) {
this.uuid = uuid;
}

View File

@@ -23,14 +23,17 @@ import com.velocitypowered.proxy.connection.registry.DimensionData;
import com.velocitypowered.proxy.connection.registry.DimensionInfo;
import com.velocitypowered.proxy.network.ProtocolUtils;
import com.velocitypowered.proxy.network.packet.Packet;
import com.velocitypowered.proxy.network.packet.PacketDirection;
import com.velocitypowered.proxy.network.packet.PacketHandler;
import com.velocitypowered.proxy.network.packet.PacketReader;
import com.velocitypowered.proxy.network.packet.PacketWriter;
import io.netty.buffer.ByteBuf;
import net.kyori.adventure.nbt.BinaryTagIO;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import org.checkerframework.checker.nullness.qual.Nullable;
// TODO: This class is in dire need of a refactor. Suppressing the warning is only done as an
// implicit acknowledgement that this code is very bad.
@SuppressWarnings("WarnAway")
public class ClientboundRespawnPacket implements Packet {
public static final PacketReader<ClientboundRespawnPacket> DECODER = PacketReader.method(ClientboundRespawnPacket::new);
public static final PacketWriter<ClientboundRespawnPacket> ENCODER = PacketWriter.deprecatedEncode();
@@ -49,13 +52,14 @@ public class ClientboundRespawnPacket implements Packet {
}
public ClientboundRespawnPacket(int dimension, long partialHashedSeed, short difficulty, short gamemode,
String levelType, boolean shouldKeepPlayerData, DimensionInfo dimensionInfo,
short previousGamemode, DimensionData currentDimensionData) {
@Nullable String levelType, boolean shouldKeepPlayerData,
DimensionInfo dimensionInfo, short previousGamemode,
DimensionData currentDimensionData) {
this.dimension = dimension;
this.partialHashedSeed = partialHashedSeed;
this.difficulty = difficulty;
this.gamemode = gamemode;
this.levelType = levelType;
this.levelType = levelType == null ? "" : levelType;
this.shouldKeepPlayerData = shouldKeepPlayerData;
this.dimensionInfo = dimensionInfo;
this.previousGamemode = previousGamemode;
@@ -119,7 +123,7 @@ public class ClientboundRespawnPacket implements Packet {
}
@Override
public void decode(ByteBuf buf, PacketDirection direction, ProtocolVersion version) {
public void decode(ByteBuf buf, ProtocolVersion version) {
String dimensionIdentifier = null;
String levelName = null;
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) {

View File

@@ -35,20 +35,12 @@ public class ClientboundStatusResponsePacket implements Packet {
public static final PacketWriter<ClientboundStatusResponsePacket> ENCODER = (buf, packet, version) ->
ProtocolUtils.writeString(buf, packet.status);
private final @Nullable CharSequence status;
private final CharSequence status;
public ClientboundStatusResponsePacket(CharSequence status) {
this.status = status;
}
@Override
public void encode(ByteBuf buf, ProtocolVersion version) {
if (status == null) {
throw new IllegalStateException("Status is not specified");
}
ProtocolUtils.writeString(buf, status);
}
@Override
public boolean handle(PacketHandler handler) {
return handler.handle(this);

View File

@@ -21,7 +21,6 @@ import com.google.common.base.MoreObjects;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.network.ProtocolUtils;
import com.velocitypowered.proxy.network.packet.Packet;
import com.velocitypowered.proxy.network.packet.PacketDirection;
import com.velocitypowered.proxy.network.packet.PacketHandler;
import com.velocitypowered.proxy.network.packet.PacketReader;
import com.velocitypowered.proxy.network.packet.PacketWriter;
@@ -69,7 +68,7 @@ public class ClientboundTabCompleteResponsePacket implements Packet {
}
@Override
public void decode(ByteBuf buf, PacketDirection direction, ProtocolVersion version) {
public void decode(ByteBuf buf, ProtocolVersion version) {
if (version.gte(ProtocolVersion.MINECRAFT_1_13)) {
this.transactionId = ProtocolUtils.readVarInt(buf);
this.start = ProtocolUtils.readVarInt(buf);
@@ -146,7 +145,7 @@ public class ClientboundTabCompleteResponsePacket implements Packet {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
if (!(o instanceof Offer)) {
return false;
}

View File

@@ -21,7 +21,6 @@ import com.google.common.base.MoreObjects;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.network.ProtocolUtils;
import com.velocitypowered.proxy.network.packet.Packet;
import com.velocitypowered.proxy.network.packet.PacketDirection;
import com.velocitypowered.proxy.network.packet.PacketHandler;
import com.velocitypowered.proxy.network.packet.PacketReader;
import com.velocitypowered.proxy.network.packet.PacketWriter;
@@ -54,7 +53,7 @@ public class ServerboundClientSettingsPacket implements Packet {
}
@Override
public void decode(ByteBuf buf, PacketDirection direction, ProtocolVersion version) {
public void decode(ByteBuf buf, ProtocolVersion version) {
this.locale = ProtocolUtils.readString(buf, 16);
this.viewDistance = buf.readByte();
this.chatVisibility = ProtocolUtils.readVarInt(buf);

View File

@@ -87,12 +87,12 @@ public class ServerboundLoginPluginResponsePacket extends DefaultByteBufHolder i
if (this == other) {
return true;
}
if (other == null || this.getClass() != other.getClass()) {
if (!(other instanceof ServerboundLoginPluginResponsePacket)) {
return false;
}
final ServerboundLoginPluginResponsePacket that = (ServerboundLoginPluginResponsePacket) other;
return this.id == that.id
&& Objects.equals(this.success, that.success)
&& this.success == that.success
&& super.equals(other);
}

View File

@@ -52,7 +52,7 @@ public class ServerboundResourcePackResponsePacket implements Packet {
@Override
public void encode(ByteBuf buf, ProtocolVersion protocolVersion) {
if (protocolVersion.lte(ProtocolVersion.MINECRAFT_1_9_4)) {
ProtocolUtils.writeString(buf, hash);
ProtocolUtils.writeString(buf, hash == null ? "" : hash);
}
ProtocolUtils.writeVarInt(buf, status.ordinal());
}

View File

@@ -25,7 +25,6 @@ import com.google.common.base.MoreObjects;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.network.ProtocolUtils;
import com.velocitypowered.proxy.network.packet.Packet;
import com.velocitypowered.proxy.network.packet.PacketDirection;
import com.velocitypowered.proxy.network.packet.PacketHandler;
import com.velocitypowered.proxy.network.packet.PacketReader;
import com.velocitypowered.proxy.network.packet.PacketWriter;
@@ -88,7 +87,7 @@ public class ServerboundTabCompleteRequestPacket implements Packet {
}
@Override
public void decode(ByteBuf buf, PacketDirection direction, ProtocolVersion version) {
public void decode(ByteBuf buf, ProtocolVersion version) {
if (version.gte(MINECRAFT_1_13)) {
this.transactionId = ProtocolUtils.readVarInt(buf);
this.command = ProtocolUtils.readString(buf, VANILLA_MAX_TAB_COMPLETE_LEN);

View File

@@ -27,7 +27,7 @@ class VarintByteDecoder implements ByteProcessor {
@Override
public boolean process(byte k) {
readVarint |= (k & 0x7F) << bytesRead++ * 7;
readVarint |= (k & 0x7F) << (bytesRead++ * 7);
if (bytesRead > 3) {
result = DecodeResult.TOO_BIG;
return false;

View File

@@ -27,7 +27,6 @@ import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap.Entry;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -85,7 +84,7 @@ public class RegularPacketRegistryMap implements PacketRegistryMap {
@Override
public @Nullable Class<? extends Packet> lookupPacket(int id) {
for (Entry<Class<?>> entry : this.classesById.object2IntEntrySet()) {
for (Object2IntMap.Entry<Class<?>> entry : this.classesById.object2IntEntrySet()) {
if (entry.getIntValue() == id) {
return (Class<? extends Packet>) entry.getKey();
}

View File

@@ -19,6 +19,7 @@ package com.velocitypowered.proxy.network.registry.protocol;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.network.packet.PacketDirection;
import com.velocitypowered.proxy.network.registry.packet.EmptyPacketRegistryMap;
import com.velocitypowered.proxy.network.registry.packet.PacketRegistryMap;
import java.util.EnumMap;
import java.util.EnumSet;
@@ -49,9 +50,9 @@ public class VersionSpecificProtocolRegistry implements ProtocolRegistry {
@Override
public PacketRegistryMap lookup(PacketDirection direction, ProtocolVersion version) {
if (direction == PacketDirection.SERVERBOUND) {
return this.serverboundByVersion.get(version);
return this.serverboundByVersion.getOrDefault(version, EmptyPacketRegistryMap.INSTANCE);
} else if (direction == PacketDirection.CLIENTBOUND) {
return this.clientboundByVersion.get(version);
return this.clientboundByVersion.getOrDefault(version, EmptyPacketRegistryMap.INSTANCE);
} else {
throw new NullPointerException("direction");
}

View File

@@ -311,6 +311,7 @@ class PlayPacketRegistry implements ProtocolRegistry {
public final PacketRegistry clientbound;
public final PacketRegistry serverbound;
@Override
public PacketRegistryMap lookup(PacketDirection direction,
ProtocolVersion version) {
return (direction == PacketDirection.SERVERBOUND ? this.serverbound : this.clientbound)
@@ -319,24 +320,21 @@ class PlayPacketRegistry implements ProtocolRegistry {
public static class PacketRegistry {
private final PacketDirection direction;
private final Map<ProtocolVersion, ProtocolRegistry> versions;
private final Map<ProtocolVersion, InternalRegistryMap> versions;
PacketRegistry(PacketDirection direction) {
this.direction = direction;
Map<ProtocolVersion, ProtocolRegistry> mutableVersions = new EnumMap<>(ProtocolVersion.class);
Map<ProtocolVersion, InternalRegistryMap> mutableVersions = new EnumMap<>(ProtocolVersion.class);
for (ProtocolVersion version : ProtocolVersion.values()) {
if (!version.isLegacy() && !version.isUnknown()) {
mutableVersions.put(version, new ProtocolRegistry(version));
mutableVersions.put(version, new InternalRegistryMap(version, direction));
}
}
this.versions = mutableVersions;
}
ProtocolRegistry getProtocolRegistry(final ProtocolVersion version) {
ProtocolRegistry registry = versions.get(version);
InternalRegistryMap getProtocolRegistry(final ProtocolVersion version) {
InternalRegistryMap registry = versions.get(version);
if (registry == null) {
throw new IllegalArgumentException("Could not find data for protocol version " + version);
}
@@ -364,7 +362,7 @@ class PlayPacketRegistry implements ProtocolRegistry {
if (protocol == to && next != current) {
break;
}
ProtocolRegistry registry = this.versions.get(protocol);
InternalRegistryMap registry = this.versions.get(protocol);
if (registry == null) {
throw new IllegalArgumentException("Unknown protocol version "
+ current.protocolVersion);
@@ -391,8 +389,12 @@ class PlayPacketRegistry implements ProtocolRegistry {
}
public void compact() {
ProtocolRegistry last = this.versions.get(MINIMUM_VERSION);
for (Entry<ProtocolVersion, ProtocolRegistry> entry : this.versions
InternalRegistryMap last = this.versions.get(MINIMUM_VERSION);
if (last == null) {
return;
}
for (Map.Entry<ProtocolVersion, InternalRegistryMap> entry : this.versions
.entrySet()) {
if (entry.getValue() == last) {
continue;
@@ -406,73 +408,79 @@ class PlayPacketRegistry implements ProtocolRegistry {
}
}
}
}
public class ProtocolRegistry implements PacketRegistryMap {
public static class InternalRegistryMap implements PacketRegistryMap {
private final ProtocolVersion version;
final IntObjectMap<PacketReader<? extends Packet>> packetIdToReader =
new IntObjectHashMap<>(16, 0.5f);
final Object2IntMap<Class<? extends Packet>> packetClassToId =
new Object2IntOpenHashMap<>(16, 0.5f);
final Map<Class<? extends Packet>, PacketWriter<? extends Packet>> packetClassToWriter =
new HashMap<>(16, 0.5f);
private final ProtocolVersion version;
final IntObjectMap<PacketReader<? extends Packet>> packetIdToReader =
new IntObjectHashMap<>(16, 0.5f);
final Object2IntMap<Class<? extends Packet>> packetClassToId =
new Object2IntOpenHashMap<>(16, 0.5f);
final Map<Class<? extends Packet>, PacketWriter<? extends Packet>> packetClassToWriter =
new HashMap<>(16, 0.5f);
private final PacketDirection direction;
ProtocolRegistry(final ProtocolVersion version) {
this.version = version;
this.packetClassToId.defaultReturnValue(Integer.MIN_VALUE);
}
InternalRegistryMap(final ProtocolVersion version,
PacketDirection direction) {
this.version = version;
this.direction = direction;
this.packetClassToId.defaultReturnValue(Integer.MIN_VALUE);
}
/**
* Attempts to create a packet from the specified {@code id}.
*
* @param id the packet ID
* @param buf the bytebuf
* @return the packet instance, or {@code null} if the ID is not registered
*/
public @Nullable Packet readPacket(final int id, ByteBuf buf, ProtocolVersion version) {
final PacketReader<? extends Packet> decoder = this.packetIdToReader.get(id);
if (decoder == null) {
return null;
}
return decoder.read(buf, version);
}
/**
* Attempts to serialize the specified {@code packet}.
*
* @param packet the packet
* @param buf the bytebuf
*/
public <P extends Packet> void writePacket(P packet, ByteBuf buf, ProtocolVersion version) {
final int id = this.packetClassToId.getInt(packet.getClass());
if (id == Integer.MIN_VALUE) {
throw new IllegalArgumentException(String.format(
"Unable to find id for packet of type %s in %s protocol %s",
packet.getClass().getName(), PacketRegistry.this.direction, this.version
));
}
@SuppressWarnings("rawtypes")
// Safe because all registering actions are type-safe.
final PacketWriter encoder = this.packetClassToWriter.get(packet.getClass());
assert encoder != null : "Couldn't look up encoder - shouldn't happen!";
ProtocolUtils.writeVarInt(buf, id);
//noinspection unchecked
encoder.write(buf, packet, version);
}
@Override
public @Nullable Class<? extends Packet> lookupPacket(int id) {
for (Object2IntMap.Entry<Class<? extends Packet>> entry : this.packetClassToId
.object2IntEntrySet()) {
if (entry.getIntValue() == id) {
return entry.getKey();
}
}
/**
* Attempts to create a packet from the specified {@code id}.
*
* @param id the packet ID
* @param buf the bytebuf
* @return the packet instance, or {@code null} if the ID is not registered
*/
@Override
public @Nullable Packet readPacket(final int id, ByteBuf buf, ProtocolVersion version) {
final PacketReader<? extends Packet> decoder = this.packetIdToReader.get(id);
if (decoder == null) {
return null;
}
return decoder.read(buf, version);
}
/**
* Attempts to serialize the specified {@code packet}.
*
* @param packet the packet
* @param buf the bytebuf
*/
@Override
public <P extends Packet> void writePacket(P packet, ByteBuf buf, ProtocolVersion version) {
final int id = this.packetClassToId.getInt(packet.getClass());
if (id == Integer.MIN_VALUE) {
throw new IllegalArgumentException(String.format(
"Unable to find id for packet of type %s in %s protocol %s",
packet.getClass().getName(), this.direction, this.version
));
}
@SuppressWarnings("rawtypes")
// Safe because all registering actions are type-safe.
final PacketWriter encoder = this.packetClassToWriter.get(packet.getClass());
if (encoder == null) {
throw new IllegalStateException("Couldn't look up encoder - shouldn't happen!");
}
ProtocolUtils.writeVarInt(buf, id);
//noinspection unchecked
encoder.write(buf, packet, version);
}
@Override
public @Nullable Class<? extends Packet> lookupPacket(int id) {
for (Object2IntMap.Entry<Class<? extends Packet>> entry : this.packetClassToId
.object2IntEntrySet()) {
if (entry.getIntValue() == id) {
return entry.getKey();
}
}
return null;
}
}

View File

@@ -35,13 +35,14 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
public final class SeparatePoolInetNameResolver extends InetNameResolver {
private final ExecutorService resolveExecutor;
private final InetNameResolver delegate;
private final Cache<String, List<InetAddress>> cache;
private AddressResolverGroup<InetSocketAddress> resolverGroup;
private @MonotonicNonNull AddressResolverGroup<InetSocketAddress> resolverGroup;
/**
* Creates a new instance of {@code SeparatePoolInetNameResolver}.

View File

@@ -60,7 +60,7 @@ public class VelocityPluginManager implements PluginManager {
private static final Logger logger = LogManager.getLogger(VelocityPluginManager.class);
private final Map<String, PluginContainer> plugins = new LinkedHashMap<>();
private final Map<Object, PluginContainer> pluginInstances = new IdentityHashMap<>();
private final IdentityHashMap<Object, PluginContainer> pluginInstances = new IdentityHashMap<>();
private final VelocityServer server;
public VelocityPluginManager(VelocityServer server) {

View File

@@ -20,11 +20,12 @@ package com.velocitypowered.proxy.plugin.loader;
import com.velocitypowered.api.plugin.PluginContainer;
import com.velocitypowered.api.plugin.PluginDescription;
import java.util.Optional;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
public class VelocityPluginContainer implements PluginContainer {
private final PluginDescription description;
private Object instance;
private @MonotonicNonNull Object instance;
public VelocityPluginContainer(PluginDescription description) {
this.description = description;
@@ -41,6 +42,10 @@ public class VelocityPluginContainer implements PluginContainer {
}
public void setInstance(Object instance) {
this.instance = instance;
if (this.instance == null) {
this.instance = instance;
} else {
throw new IllegalStateException("Plugin instance already set");
}
}
}

View File

@@ -39,7 +39,7 @@ public class VelocityPluginDescription implements PluginDescription {
private final @Nullable String url;
private final List<String> authors;
private final Map<String, PluginDependency> dependencies;
private final Path source;
private final @Nullable Path source;
/**
* Creates a new plugin description.
@@ -54,7 +54,8 @@ public class VelocityPluginDescription implements PluginDescription {
*/
public VelocityPluginDescription(String id, @Nullable String name, @Nullable String version,
@Nullable String description, @Nullable String url,
@Nullable List<String> authors, Collection<PluginDependency> dependencies, Path source) {
@Nullable List<String> authors, Collection<PluginDependency> dependencies,
@Nullable Path source) {
this.id = checkNotNull(id, "id");
this.name = Strings.emptyToNull(name);
this.version = Strings.emptyToNull(version);

View File

@@ -20,10 +20,10 @@ package com.velocitypowered.proxy.plugin.loader.java;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.velocitypowered.annotationprocessor.SerializedPluginDescription;
import com.velocitypowered.api.plugin.InvalidPluginException;
import com.velocitypowered.api.plugin.PluginContainer;
import com.velocitypowered.api.plugin.PluginDescription;
import com.velocitypowered.api.plugin.ap.SerializedPluginDescription;
import com.velocitypowered.api.plugin.meta.PluginDependency;
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.proxy.VelocityServer;
@@ -48,11 +48,9 @@ import java.util.jar.JarInputStream;
public class JavaPluginLoader implements PluginLoader {
private final ProxyServer server;
private final Path baseDirectory;
public JavaPluginLoader(ProxyServer server, Path baseDirectory) {
this.server = server;
this.baseDirectory = baseDirectory;
}
@@ -60,7 +58,7 @@ public class JavaPluginLoader implements PluginLoader {
public PluginDescription loadPluginDescription(Path source) throws Exception {
Optional<SerializedPluginDescription> serialized = getSerializedPluginInfo(source);
if (!serialized.isPresent()) {
if (serialized.isEmpty()) {
throw new InvalidPluginException("Did not find a valid velocity-plugin.json.");
}
@@ -79,7 +77,9 @@ public class JavaPluginLoader implements PluginLoader {
}
Path jarFilePath = source.file();
assert jarFilePath != null;
if (jarFilePath == null) {
throw new IllegalStateException("JAR path not provided.");
}
URL pluginJarUrl = jarFilePath.toUri().toURL();
PluginClassLoader loader = AccessController.doPrivileged(
@@ -106,7 +106,7 @@ public class JavaPluginLoader implements PluginLoader {
throw new IllegalArgumentException("No path in plugin description");
}
return new VelocityPluginModule(server, javaDescription, container, baseDirectory);
return new VelocityPluginModule(javaDescription, container, baseDirectory);
}
@Override

View File

@@ -32,8 +32,8 @@ class JavaVelocityPluginDescription extends VelocityPluginDescription {
JavaVelocityPluginDescription(String id, @Nullable String name, @Nullable String version,
@Nullable String description, @Nullable String url,
@Nullable List<String> authors, Collection<PluginDependency> dependencies, Path source,
Class<?> mainClass) {
@Nullable List<String> authors, Collection<PluginDependency> dependencies,
@Nullable Path source, Class<?> mainClass) {
super(id, name, version, description, url, authors, dependencies, source);
this.mainClass = checkNotNull(mainClass);
}

View File

@@ -30,14 +30,12 @@ import org.slf4j.LoggerFactory;
class VelocityPluginModule implements Module {
private final ProxyServer server;
private final JavaVelocityPluginDescription description;
private final PluginContainer pluginContainer;
private final Path basePluginPath;
VelocityPluginModule(ProxyServer server, JavaVelocityPluginDescription description,
PluginContainer pluginContainer, Path basePluginPath) {
this.server = server;
VelocityPluginModule(JavaVelocityPluginDescription description,
PluginContainer pluginContainer, Path basePluginPath) {
this.description = description;
this.pluginContainer = pluginContainer;
this.basePluginPath = basePluginPath;

View File

@@ -61,12 +61,12 @@ import org.checkerframework.checker.nullness.qual.Nullable;
public class VelocityRegisteredServer implements RegisteredServer, ForwardingAudience {
private final @Nullable VelocityServer server;
private final @Nullable VelocityServer instance;
private final ServerInfo serverInfo;
private final Map<UUID, ConnectedPlayer> players = new ConcurrentHashMap<>();
public VelocityRegisteredServer(@Nullable VelocityServer server, ServerInfo serverInfo) {
this.server = server;
public VelocityRegisteredServer(@Nullable VelocityServer instance, ServerInfo serverInfo) {
this.instance = instance;
this.serverInfo = Preconditions.checkNotNull(serverInfo, "serverInfo");
}
@@ -93,18 +93,19 @@ public class VelocityRegisteredServer implements RegisteredServer, ForwardingAud
* @return the server list ping response
*/
public CompletableFuture<ServerPing> ping(@Nullable EventLoop loop, ProtocolVersion version) {
if (server == null) {
VelocityServer instance = this.instance;
if (instance == null) {
throw new IllegalStateException("No Velocity proxy instance available");
}
CompletableFuture<ServerPing> pingFuture = new CompletableFuture<>();
server.createBootstrap(loop, serverInfo.address())
.handler(new ChannelInitializer<Channel>() {
instance.createBootstrap(loop, serverInfo.address())
.handler(new ChannelInitializer<>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline()
.addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder())
.addLast(READ_TIMEOUT,
new ReadTimeoutHandler(server.configuration().getReadTimeout(),
new ReadTimeoutHandler(instance.configuration().getReadTimeout(),
TimeUnit.MILLISECONDS))
.addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE)
.addLast(MINECRAFT_DECODER,
@@ -112,7 +113,7 @@ public class VelocityRegisteredServer implements RegisteredServer, ForwardingAud
.addLast(MINECRAFT_ENCODER,
new MinecraftEncoder(PacketDirection.SERVERBOUND));
ch.pipeline().addLast(HANDLER, new MinecraftConnection(ch, server));
ch.pipeline().addLast(HANDLER, new MinecraftConnection(ch, instance));
}
})
.connect(serverInfo.address())

View File

@@ -144,7 +144,9 @@ public class VelocityTabList implements TabList {
// Packets are already forwarded on, so no need to do that here
for (ClientboundPlayerListItemPacket.Item item : packet.getItems()) {
UUID uuid = item.getUuid();
assert uuid != null : "1.7 tab list entry given to modern tab list handler!";
if (uuid == null) {
throw new IllegalStateException("1.7 tab list entry given to modern tab list handler!");
}
if (packet.getAction() != ClientboundPlayerListItemPacket.ADD_PLAYER
&& !entries.containsKey(uuid)) {
@@ -160,7 +162,7 @@ public class VelocityTabList implements TabList {
if (name == null || properties == null) {
throw new IllegalStateException("Got null game profile for ADD_PLAYER");
}
entries.put(item.getUuid(), (VelocityTabListEntry) TabListEntry.builder()
entries.put(uuid, (VelocityTabListEntry) TabListEntry.builder()
.tabList(this)
.profile(new GameProfile(uuid, name, properties))
.displayName(item.getDisplayName())

View File

@@ -28,12 +28,12 @@ public class VelocityTabListEntry implements TabListEntry {
private final VelocityTabList tabList;
private final GameProfile profile;
private net.kyori.adventure.text.Component displayName;
private @Nullable Component displayName;
private int latency;
private int gameMode;
VelocityTabListEntry(VelocityTabList tabList, GameProfile profile,
net.kyori.adventure.text.@Nullable Component displayName, int latency, int gameMode) {
@Nullable Component displayName, int latency, int gameMode) {
this.tabList = tabList;
this.profile = profile;
this.displayName = displayName;
@@ -57,13 +57,13 @@ public class VelocityTabListEntry implements TabListEntry {
}
@Override
public TabListEntry setDisplayName(net.kyori.adventure.text.@Nullable Component displayName) {
public TabListEntry setDisplayName(@Nullable Component displayName) {
this.displayName = displayName;
tabList.updateEntry(ClientboundPlayerListItemPacket.UPDATE_DISPLAY_NAME, this);
return this;
}
void setDisplayNameInternal(net.kyori.adventure.text.@Nullable Component displayName) {
void setDisplayNameInternal(@Nullable Component displayName) {
this.displayName = displayName;
}

View File

@@ -17,6 +17,8 @@
package com.velocitypowered.proxy.util;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.net.URI;
@@ -56,7 +58,7 @@ public class FileSystemUtils {
}
if (knownResource.getProtocol().equals("jar")) {
// Running from a JAR
String jarPathRaw = knownResource.toString().split("!")[0];
String jarPathRaw = Iterables.get(Splitter.on('!').split(knownResource.toString()), 0);
URI path = URI.create(jarPathRaw + "!/");
try (FileSystem fileSystem = FileSystems.newFileSystem(path, Map.of("create", "true"))) {

View File

@@ -17,6 +17,7 @@
package com.velocitypowered.proxy.util;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
@@ -154,19 +155,19 @@ public enum InformationUtils {
|| v6.isSiteLocalAddress()) {
return address.getHostAddress();
} else {
String[] bits = v6.getHostAddress().split(":");
List<String> bits = Splitter.on(':').splitToList(v6.getHostAddress());
String ret = "";
boolean flag = false;
for (int iter = 0; iter < bits.length; iter++) {
for (int iter = 0; iter < bits.size(); iter++) {
if (flag) {
ret += ":X";
continue;
}
if (!bits[iter].equals("0")) {
if (!bits.get(iter).equals("0")) {
if (iter == 0) {
ret = bits[iter];
ret = bits.get(iter);
} else {
ret = "::" + bits[iter];
ret = "::" + bits.get(iter);
}
flag = true;
}

View File

@@ -274,7 +274,7 @@ public class AdventureBossBarManager implements BossBar.Listener {
private byte serializeFlags(Set<Flag> flags) {
byte val = 0x0;
for (Flag flag : flags) {
val |= FLAG_BITS_TO_PROTOCOL.get(flag);
val = (byte) (val | FLAG_BITS_TO_PROTOCOL.get(flag));
}
return val;
}

View File

@@ -25,6 +25,7 @@ import com.velocitypowered.api.event.PostOrder;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.proxy.testutil.FakePluginManager;
import java.util.concurrent.atomic.AtomicInteger;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
@@ -70,7 +71,7 @@ public class EventTest {
static final class AlwaysSyncListener {
Thread thread;
@MonotonicNonNull Thread thread;
int result;
@Subscribe
@@ -92,9 +93,9 @@ public class EventTest {
static final class AlwaysAsyncListener {
Thread threadA;
Thread threadB;
Thread threadC;
@MonotonicNonNull Thread threadA;
@MonotonicNonNull Thread threadB;
@MonotonicNonNull Thread threadC;
int result;
@Subscribe(async = true)
@@ -129,10 +130,10 @@ public class EventTest {
static final class SometimesAsyncListener {
Thread threadA;
Thread threadB;
Thread threadC;
Thread threadD;
@MonotonicNonNull Thread threadA;
@MonotonicNonNull Thread threadB;
@MonotonicNonNull Thread threadC;
@MonotonicNonNull Thread threadD;
int result;
@Subscribe(order = PostOrder.EARLY)
@@ -169,9 +170,9 @@ public class EventTest {
static final class ContinuationListener {
Thread threadA;
Thread threadB;
Thread threadC;
@MonotonicNonNull Thread threadA;
@MonotonicNonNull Thread threadB;
@MonotonicNonNull Thread threadC;
final AtomicInteger value = new AtomicInteger();
@@ -211,9 +212,9 @@ public class EventTest {
static final class AsyncContinuationListener {
Thread threadA;
Thread threadB;
Thread threadC;
@MonotonicNonNull Thread threadA;
@MonotonicNonNull Thread threadB;
@MonotonicNonNull Thread threadC;
final AtomicInteger value = new AtomicInteger();
@@ -253,9 +254,9 @@ public class EventTest {
static final class ResumeContinuationImmediatelyListener {
Thread threadA;
Thread threadB;
Thread threadC;
@MonotonicNonNull Thread threadA;
@MonotonicNonNull Thread threadB;
@MonotonicNonNull Thread threadC;
int result;
@Subscribe(order = PostOrder.EARLY)