Plugin API (#34)

The Velocity API has had a lot of community input (special thanks to @hugmanrique who started the work, @lucko who contributed permissions support, and @Minecrell for providing initial feedback and an initial version of ServerListPlus).

While the API is far from complete, there is enough available for people to start doing useful stuff with Velocity.
This commit is contained in:
Andrew Steinborn
2018-08-20 19:30:32 -04:00
committed by GitHub
parent 8e836a5066
commit a028467e66
89 changed files with 3453 additions and 358 deletions

View File

@@ -0,0 +1,87 @@
package com.velocitypowered.api.plugin.ap;
import com.google.gson.Gson;
import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.plugin.PluginDescription;
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;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.*;
@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 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 (!PluginDescription.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;
}
}

View File

@@ -0,0 +1,125 @@
package com.velocitypowered.api.plugin.ap;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.velocitypowered.api.plugin.Plugin;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class SerializedPluginDescription {
private final String id;
private final String author;
private final String main;
private final String version;
private final List<Dependency> dependencies;
public SerializedPluginDescription(String id, String author, String main, String version) {
this(id, author, main, version, ImmutableList.of());
}
public SerializedPluginDescription(String id, String author, String main, String version, List<Dependency> dependencies) {
this.id = Preconditions.checkNotNull(id, "id");
this.author = Preconditions.checkNotNull(author, "author");
this.main = Preconditions.checkNotNull(main, "main");
this.version = Preconditions.checkNotNull(version, "version");
this.dependencies = ImmutableList.copyOf(dependencies);
}
public 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.author(), qualifiedName, plugin.version(), dependencies);
}
public String getId() {
return id;
}
public String getAuthor() {
return author;
}
public String getMain() {
return main;
}
public String getVersion() {
return version;
}
public List<Dependency> getDependencies() {
return dependencies;
}
@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(author, that.author) &&
Objects.equals(main, that.main) &&
Objects.equals(version, that.version) &&
Objects.equals(dependencies, that.dependencies);
}
@Override
public int hashCode() {
return Objects.hash(id, author, main, version, dependencies);
}
@Override
public String toString() {
return "SerializedPluginDescription{" +
"id='" + id + '\'' +
", author='" + author + '\'' +
", main='" + main + '\'' +
", version='" + version + '\'' +
", dependencies=" + dependencies +
'}';
}
public static 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 +
'}';
}
}
}

View File

@@ -0,0 +1 @@
com.velocitypowered.api.plugin.ap.PluginAnnotationProcessor