mirror of
https://github.com/PaperMC/Velocity.git
synced 2026-02-17 14:37:43 +01:00
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:
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* The Velocity API is licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in the api top-level directory.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.api.plugin.ap;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.velocitypowered.api.plugin.Plugin;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.Name;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.FileObject;
|
||||
import javax.tools.StandardLocation;
|
||||
|
||||
@SupportedAnnotationTypes({"com.velocitypowered.api.plugin.Plugin"})
|
||||
public class PluginAnnotationProcessor extends AbstractProcessor {
|
||||
|
||||
private ProcessingEnvironment environment;
|
||||
private String pluginClassFound;
|
||||
private boolean warnedAboutMultiplePlugins;
|
||||
|
||||
@Override
|
||||
public synchronized void init(ProcessingEnvironment processingEnv) {
|
||||
this.environment = processingEnv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceVersion getSupportedSourceVersion() {
|
||||
return SourceVersion.latestSupported();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean process(Set<? extends TypeElement> annotations,
|
||||
RoundEnvironment roundEnv) {
|
||||
if (roundEnv.processingOver()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Element element : roundEnv.getElementsAnnotatedWith(Plugin.class)) {
|
||||
if (element.getKind() != ElementKind.CLASS) {
|
||||
environment.getMessager()
|
||||
.printMessage(Diagnostic.Kind.ERROR, "Only classes can be annotated with "
|
||||
+ Plugin.class.getCanonicalName());
|
||||
return false;
|
||||
}
|
||||
|
||||
Name qualifiedName = ((TypeElement) element).getQualifiedName();
|
||||
|
||||
if (Objects.equals(pluginClassFound, qualifiedName.toString())) {
|
||||
if (!warnedAboutMultiplePlugins) {
|
||||
environment.getMessager()
|
||||
.printMessage(Diagnostic.Kind.WARNING, "Velocity does not yet currently support "
|
||||
+ "multiple plugins. We are using " + pluginClassFound
|
||||
+ " for your plugin's main class.");
|
||||
warnedAboutMultiplePlugins = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Plugin plugin = element.getAnnotation(Plugin.class);
|
||||
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 "
|
||||
+ "contain dashes or underscores.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// All good, generate the velocity-plugin.json.
|
||||
SerializedPluginDescription description = SerializedPluginDescription
|
||||
.from(plugin, qualifiedName.toString());
|
||||
try {
|
||||
FileObject object = environment.getFiler()
|
||||
.createResource(StandardLocation.CLASS_OUTPUT, "", "velocity-plugin.json");
|
||||
try (Writer writer = new BufferedWriter(object.openWriter())) {
|
||||
new Gson().toJson(description, writer);
|
||||
}
|
||||
pluginClassFound = qualifiedName.toString();
|
||||
} catch (IOException e) {
|
||||
environment.getMessager()
|
||||
.printMessage(Diagnostic.Kind.ERROR, "Unable to generate plugin file");
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* The Velocity API is licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in the api top-level directory.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.api.plugin.ap;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.velocitypowered.api.plugin.Plugin;
|
||||
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 final 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;
|
||||
private final @Nullable String version;
|
||||
private final @Nullable String description;
|
||||
private final @Nullable String url;
|
||||
private final @Nullable List<String> authors;
|
||||
private final @Nullable List<Dependency> dependencies;
|
||||
private final String main;
|
||||
|
||||
private SerializedPluginDescription(String id, String name, String version, String description,
|
||||
String url,
|
||||
List<String> authors, List<Dependency> dependencies, String main) {
|
||||
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);
|
||||
this.url = Strings.emptyToNull(url);
|
||||
this.authors = authors == null || authors.isEmpty() ? ImmutableList.of() : authors;
|
||||
this.dependencies =
|
||||
dependencies == null || dependencies.isEmpty() ? ImmutableList.of() : dependencies;
|
||||
this.main = Preconditions.checkNotNull(main, "main");
|
||||
}
|
||||
|
||||
static SerializedPluginDescription from(Plugin plugin, String qualifiedName) {
|
||||
List<Dependency> dependencies = new ArrayList<>();
|
||||
for (com.velocitypowered.api.plugin.Dependency dependency : plugin.dependencies()) {
|
||||
dependencies.add(new Dependency(dependency.id(), dependency.optional()));
|
||||
}
|
||||
return new SerializedPluginDescription(plugin.id(), plugin.name(), plugin.version(),
|
||||
plugin.description(), plugin.url(),
|
||||
Arrays.stream(plugin.authors()).filter(author -> !author.isEmpty())
|
||||
.collect(Collectors.toList()), dependencies, qualifiedName);
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public @Nullable String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public @Nullable String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public @Nullable String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public @Nullable String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public List<String> getAuthors() {
|
||||
return authors == null ? ImmutableList.of() : authors;
|
||||
}
|
||||
|
||||
public List<Dependency> getDependencies() {
|
||||
return dependencies == null ? ImmutableList.of() : dependencies;
|
||||
}
|
||||
|
||||
public String getMain() {
|
||||
return main;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
SerializedPluginDescription that = (SerializedPluginDescription) o;
|
||||
return Objects.equals(id, that.id)
|
||||
&& Objects.equals(name, that.name)
|
||||
&& Objects.equals(version, that.version)
|
||||
&& Objects.equals(description, that.description)
|
||||
&& Objects.equals(url, that.url)
|
||||
&& Objects.equals(authors, that.authors)
|
||||
&& Objects.equals(dependencies, that.dependencies)
|
||||
&& Objects.equals(main, that.main);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, name, version, description, url, authors, dependencies);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SerializedPluginDescription{"
|
||||
+ "id='" + id + '\''
|
||||
+ ", name='" + name + '\''
|
||||
+ ", version='" + version + '\''
|
||||
+ ", description='" + description + '\''
|
||||
+ ", url='" + url + '\''
|
||||
+ ", authors=" + authors
|
||||
+ ", dependencies=" + dependencies
|
||||
+ ", main='" + main + '\''
|
||||
+ '}';
|
||||
}
|
||||
|
||||
public static final class Dependency {
|
||||
|
||||
private final String id;
|
||||
private final boolean optional;
|
||||
|
||||
public Dependency(String id, boolean optional) {
|
||||
this.id = id;
|
||||
this.optional = optional;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean isOptional() {
|
||||
return optional;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Dependency that = (Dependency) o;
|
||||
return optional == that.optional
|
||||
&& Objects.equals(id, that.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, optional);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Dependency{"
|
||||
+ "id='" + id + '\''
|
||||
+ ", optional=" + optional
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
com.velocitypowered.api.plugin.ap.PluginAnnotationProcessor
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
package com.velocitypowered.api.event;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Allows a listener to receive direct dispatches of events. This interface can be used directly
|
||||
* by a listener (using {@link EventManager#register(Object, Class, short, EventHandler)} or
|
||||
@@ -15,5 +17,5 @@ package com.velocitypowered.api.event;
|
||||
@FunctionalInterface
|
||||
public interface EventHandler<E> {
|
||||
|
||||
EventTask execute(E event);
|
||||
@Nullable EventTask execute(E event);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,9 @@ public interface EventManager {
|
||||
*
|
||||
* @param event the event to fire
|
||||
*/
|
||||
@SuppressWarnings("FutureReturnValueIgnored")
|
||||
default void fireAndForget(Object event) {
|
||||
// Calling fire(Object) and not handling it is intentional.
|
||||
fire(event);
|
||||
}
|
||||
|
||||
|
||||
@@ -174,6 +174,9 @@ public abstract class EventTask {
|
||||
* @param future The task to wait for
|
||||
* @return The event task
|
||||
*/
|
||||
// The Error Prone annotation here is spurious. The Future is handled via the CompletableFuture
|
||||
// API, which does NOT use the traditional blocking model.
|
||||
@SuppressWarnings("FutureReturnValueIgnored")
|
||||
public static EventTask.WithContinuation resumeWhenComplete(
|
||||
final CompletableFuture<?> future) {
|
||||
requireNonNull(future, "future");
|
||||
|
||||
@@ -88,7 +88,7 @@ public interface ResultedEvent<R extends ResultedEvent.Result> {
|
||||
|
||||
private final @Nullable Component reason;
|
||||
|
||||
protected ComponentResult(@Nullable Component reason) {
|
||||
private ComponentResult(@Nullable Component reason) {
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ public final class ConnectionHandshakeEventImpl implements ConnectionHandshakeEv
|
||||
private final String originalHostname;
|
||||
private String currentHostname;
|
||||
private ComponentResult result;
|
||||
private SocketAddress currentRemoteAddress;
|
||||
private @Nullable SocketAddress currentRemoteAddress;
|
||||
|
||||
public ConnectionHandshakeEventImpl(InboundConnection connection,
|
||||
String originalHostname) {
|
||||
@@ -59,7 +59,7 @@ public final class ConnectionHandshakeEventImpl implements ConnectionHandshakeEv
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentRemoteHostAddress(SocketAddress address) {
|
||||
public void setCurrentRemoteHostAddress(@Nullable SocketAddress address) {
|
||||
currentRemoteAddress = address;
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ public interface KickedFromServerEvent extends
|
||||
*/
|
||||
final class RedirectPlayer implements ServerKickResult {
|
||||
|
||||
private final Component message;
|
||||
private final @Nullable Component message;
|
||||
private final RegisteredServer server;
|
||||
|
||||
private RedirectPlayer(RegisteredServer server,
|
||||
@@ -148,7 +148,7 @@ public interface KickedFromServerEvent extends
|
||||
return server;
|
||||
}
|
||||
|
||||
public Component message() {
|
||||
public @Nullable Component message() {
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
public class ServerPostConnectEventImpl implements ServerPostConnectEvent {
|
||||
|
||||
private final Player player;
|
||||
private final RegisteredServer previousServer;
|
||||
private final @Nullable RegisteredServer previousServer;
|
||||
|
||||
public ServerPostConnectEventImpl(Player player,
|
||||
@Nullable RegisteredServer previousServer) {
|
||||
|
||||
@@ -98,7 +98,7 @@ public interface ServerPreConnectEvent extends ResultedEvent<ServerPreConnectEve
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
if (!(o instanceof ServerResult)) {
|
||||
return false;
|
||||
}
|
||||
ServerResult that = (ServerResult) o;
|
||||
|
||||
@@ -60,7 +60,7 @@ public enum ProtocolVersion implements Ordered<ProtocolVersion> {
|
||||
|
||||
private final int protocol;
|
||||
private final int snapshotProtocol;
|
||||
private final String[] names;
|
||||
private final ImmutableList<String> names;
|
||||
|
||||
/**
|
||||
* Represents the lowest supported version.
|
||||
@@ -127,7 +127,7 @@ public enum ProtocolVersion implements Ordered<ProtocolVersion> {
|
||||
}
|
||||
|
||||
this.protocol = protocol;
|
||||
this.names = names;
|
||||
this.names = ImmutableList.copyOf(names);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,7 +146,7 @@ public enum ProtocolVersion implements Ordered<ProtocolVersion> {
|
||||
* @return the version name
|
||||
*/
|
||||
public String versionIntroducedIn() {
|
||||
return names[0];
|
||||
return names.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,7 +156,7 @@ public enum ProtocolVersion implements Ordered<ProtocolVersion> {
|
||||
* @return the version name
|
||||
*/
|
||||
public String mostRecentSupportedVersion() {
|
||||
return names[names.length - 1];
|
||||
return names.get(names.size() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,7 @@ public interface InboundConnection {
|
||||
*
|
||||
* @return the player's remote address
|
||||
*/
|
||||
SocketAddress remoteAddress();
|
||||
@Nullable SocketAddress remoteAddress();
|
||||
|
||||
/**
|
||||
* Returns the hostname that the user entered into the client, if applicable.
|
||||
|
||||
@@ -148,7 +148,7 @@ public interface Player extends CommandSource, Identified, InboundConnection,
|
||||
* from the player, you should use the equivalent method on the instance returned by
|
||||
* {@link #connectedServer()}.
|
||||
*
|
||||
* @inheritDoc
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
boolean sendPluginMessage(PluginChannelId identifier, byte[] data);
|
||||
|
||||
@@ -33,14 +33,14 @@ public final class QueryResponse {
|
||||
private final int maxPlayers;
|
||||
private final String proxyHost;
|
||||
private final int proxyPort;
|
||||
private final ImmutableCollection<String> players;
|
||||
private final ImmutableList<String> players;
|
||||
private final String proxyVersion;
|
||||
private final ImmutableCollection<PluginInformation> plugins;
|
||||
private final ImmutableList<PluginInformation> plugins;
|
||||
|
||||
@VisibleForTesting
|
||||
QueryResponse(String hostname, String gameVersion, String map, int onlinePlayers,
|
||||
int maxPlayers, String proxyHost, int proxyPort, ImmutableCollection<String> players,
|
||||
String proxyVersion, ImmutableCollection<PluginInformation> plugins) {
|
||||
int maxPlayers, String proxyHost, int proxyPort, ImmutableList<String> players,
|
||||
String proxyVersion, ImmutableList<PluginInformation> plugins) {
|
||||
this.hostname = hostname;
|
||||
this.gameVersion = gameVersion;
|
||||
this.map = map;
|
||||
|
||||
@@ -150,7 +150,7 @@ public final class ServerPing {
|
||||
private final List<SamplePlayer> samplePlayers = new ArrayList<>();
|
||||
private String modType = "FML";
|
||||
private final List<ModInfo.Mod> mods = new ArrayList<>();
|
||||
private Component description;
|
||||
private @Nullable Component description;
|
||||
private @Nullable Favicon favicon;
|
||||
private boolean nullOutPlayers;
|
||||
private boolean nullOutModinfo;
|
||||
|
||||
Reference in New Issue
Block a user