diff --git a/build.gradle b/build.gradle index 41ba86c..f1c8306 100644 --- a/build.gradle +++ b/build.gradle @@ -83,6 +83,18 @@ dependencies { testImplementation 'org.hamcrest:hamcrest:2.2' } +task buildResources { + doLast { + File to = new File("${buildDir}/classes/java/main/META-INF/services/javax.annotation.processing.Processor") + to.parentFile.mkdirs() + if (!to.exists()) { + to.createNewFile() + to.append("de.steamwar.linkage.LinkageProcessor\n") + } + } +} +classes.finalizedBy(buildResources) + task buildProject { description 'Build this project' group "Steamwar" diff --git a/src/de/steamwar/linkage/AllowedContexts.java b/src/de/steamwar/linkage/AllowedContexts.java new file mode 100644 index 0000000..775aaf5 --- /dev/null +++ b/src/de/steamwar/linkage/AllowedContexts.java @@ -0,0 +1,36 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.ANNOTATION_TYPE) +@Retention(RetentionPolicy.CLASS) +public @interface AllowedContexts { + + /** + * The context in which this annotation is valid. + */ + LinkageType.Context[] value(); + +} diff --git a/src/de/steamwar/linkage/DiscordMode.java b/src/de/steamwar/linkage/DiscordMode.java new file mode 100644 index 0000000..f30bab8 --- /dev/null +++ b/src/de/steamwar/linkage/DiscordMode.java @@ -0,0 +1,31 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@AllowedContexts(LinkageType.Context.BUNGEE) +@Retention(RetentionPolicy.SOURCE) +@Target({ElementType.TYPE}) +public @interface DiscordMode { +} diff --git a/src/de/steamwar/linkage/EventMode.java b/src/de/steamwar/linkage/EventMode.java new file mode 100644 index 0000000..86c8528 --- /dev/null +++ b/src/de/steamwar/linkage/EventMode.java @@ -0,0 +1,44 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@AllowedContexts(LinkageType.Context.BUNGEE) +@Retention(RetentionPolicy.SOURCE) +@Target({ElementType.TYPE}) +public @interface EventMode { + Mode value(); + + @AllArgsConstructor + enum Mode { + EventOnly(""), + NonEvent("!"); + + @Getter + private String prefix; + } +} diff --git a/src/de/steamwar/linkage/LinkageProcessor.java b/src/de/steamwar/linkage/LinkageProcessor.java new file mode 100644 index 0000000..6f0fbd9 --- /dev/null +++ b/src/de/steamwar/linkage/LinkageProcessor.java @@ -0,0 +1,352 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage; + +import de.steamwar.linkage.plan.BuildPlan; +import de.steamwar.linkage.plan.FieldBuilder; +import de.steamwar.linkage.plan.MethodBuilder; +import de.steamwar.linkage.plan.ParameterBuilder; +import lombok.Getter; +import lombok.SneakyThrows; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.Messager; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.*; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; +import javax.tools.Diagnostic; +import java.io.*; +import java.io.Writer; +import java.lang.annotation.Annotation; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class LinkageProcessor extends AbstractProcessor { + + @Getter + private static LinkageType.Context context; + + @Getter + private static String pluginMain; + + private String name; + private String packageName; + private String className; + + private Messager messager; + private boolean processed = false; + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + + @Override + public Set getSupportedAnnotationTypes() { + return Stream.of(Linked.class, Linked.Linkages.class) + .map(Class::getCanonicalName) + .collect(Collectors.toSet()); + } + + @SneakyThrows + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + + String name = new File(System.getProperty("user.dir")).getName(); + if (name.contains(".")) name = name.substring(0, name.indexOf('.')); + name = name.toLowerCase(); + + messager = processingEnv.getMessager(); + + this.name = name; + packageName = "de.steamwar." + name + ".linkage"; + className = "LinkageUtils"; + mainClass(); + } + + @SneakyThrows + private void mainClass() { + File file = new File(System.getProperty("user.dir")); + Optional pluginYMLFile = Files.walk(file.toPath()) + .map(Path::toFile) + .filter(File::isFile) + .filter(f -> f.getName().equals("plugin.yml") || f.getName().equals("bungee.yml")) + .findFirst(); + if (!pluginYMLFile.isPresent()) { + messager.printMessage(Diagnostic.Kind.ERROR, "Could not find plugin.yml or bungee.yml"); + return; + } + context = pluginYMLFile.get().getName().equals("bungee.yml") ? LinkageType.Context.BUNGEE : LinkageType.Context.SPIGOT; + Optional mainName = getMainName(pluginYMLFile.get()); + if (!mainName.isPresent()) { + messager.printMessage(Diagnostic.Kind.ERROR, "Could not find main class in plugin.yml or bungee.yml"); + return; + } + pluginMain = mainName.get(); + } + + @SneakyThrows + private Optional getMainName(File pluginYML) { + if (!pluginYML.exists()) return Optional.empty(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(pluginYML)))) { + return reader.lines() + .filter(line -> line.startsWith("main:")) + .map(line -> line.substring(line.indexOf(':') + 1).trim()) + .findFirst(); + } + } + + @SneakyThrows + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (processed) return false; + processed = true; + + Writer writer = processingEnv.getFiler().createSourceFile("de.steamwar." + name + ".linkage.LinkageUtils").openWriter(); + + BuildPlan buildPlan = new BuildPlan(packageName, className); + buildPlan.addImport("java.util.Set"); + buildPlan.addImport("java.lang.Class"); + buildPlan.addImport("de.steamwar.linkage.LinkageType"); + buildPlan.addImport("java.util.HashSet"); + buildPlan.addField(new FieldBuilder("Set>", "enabled", "new HashSet<>()")); + + MethodBuilder runsMethod = new MethodBuilder("run", "void"); + runsMethod.addParameter(new ParameterBuilder("Class...", "types")); + runsMethod.addLine("for (Class type : types) _run(type);"); + buildPlan.addMethod(runsMethod); + + + MethodBuilder runMethod = new MethodBuilder("_run", "void"); + runMethod.setPrivate(true); + buildPlan.addMethod(runMethod); + runMethod.addParameter(new ParameterBuilder("Class", "type")); + runMethod.addLine("if (!enabled.add(type)) return;"); + Set> alreadyGenerated = new HashSet<>(); + + Set elements = roundEnv.getElementsAnnotatedWith(Linked.class); + elements.addAll((Set) roundEnv.getElementsAnnotatedWith(Linked.Linkages.class)); + + Map neededFields = new HashMap<>(); + for (Element element : elements) { + if (element.getKind() != ElementKind.CLASS) { + continue; + } + TypeElement typeElement = (TypeElement) element; + Linked[] linkeds = element.getAnnotationsByType(Linked.class); + if (linkeds.length == 0) { + continue; + } + + if (linkeds.length > 1) { + neededFields.put(typeElement.getQualifiedName().toString(), typeElement); + } + + List variableElements = typeElement.getEnclosedElements().stream().filter(e -> e.getKind() == ElementKind.FIELD).map(VariableElement.class::cast).filter(e -> { + return e.getAnnotation(LinkedInstance.class) != null; + }).collect(Collectors.toList()); + if (variableElements.isEmpty()) { + continue; + } + + for (VariableElement variableElement : variableElements) { + if (!variableElement.getModifiers().contains(Modifier.PUBLIC)) { + messager.printMessage(Diagnostic.Kind.ERROR, "Field " + variableElement.getSimpleName() + " must be public", variableElement); + continue; + } + if (variableElement.getModifiers().contains(Modifier.STATIC)) { + messager.printMessage(Diagnostic.Kind.ERROR, "Field " + variableElement.getSimpleName() + " must be non static", variableElement); + continue; + } + if (variableElement.getModifiers().contains(Modifier.FINAL)) { + messager.printMessage(Diagnostic.Kind.ERROR, "Field " + variableElement.getSimpleName() + " must be non final", variableElement); + continue; + } + neededFields.put(typeElement.getQualifiedName().toString(), typeElement); + TypeElement fieldType = (TypeElement) ((DeclaredType) variableElement.asType()).asElement(); + neededFields.put(fieldType.getQualifiedName().toString(), fieldType); + + specialElements(typeElement, buildPlan, buildPlan::addStaticLine, () -> { + buildPlan.addStaticLine(getElement(typeElement, neededFields) + "." + variableElement.getSimpleName().toString() + " = " + getElement((TypeElement) ((DeclaredType) variableElement.asType()).asElement(), neededFields) + ";"); + }); + } + } + neededFields.forEach((s, typeElement) -> { + buildPlan.addImport(typeElement.getQualifiedName().toString()); + buildPlan.addField(new FieldBuilder(typeElement.getSimpleName().toString(), typeElement.getSimpleName().toString())); + + MethodBuilder initializer = new MethodBuilder(typeElement.getSimpleName().toString(), typeElement.getSimpleName().toString()); + initializer.setPrivate(true); + specialElements(typeElement, buildPlan, initializer::addLine, () -> { + initializer.addLine("if (" + typeElement.getSimpleName().toString() + " == null) {"); + initializer.addLine(" " + typeElement.getSimpleName().toString() + " = new " + typeElement.getSimpleName().toString() + "();"); + initializer.addLine("}"); + }); + initializer.addLine("return " + typeElement.getSimpleName().toString() + ";"); + buildPlan.addMethod(initializer); + }); + + Map, MethodBuilder> methods = new HashMap<>(); + for (Element element : elements) { + if (element.getKind() != ElementKind.CLASS) { + continue; + } + TypeElement typeElement = (TypeElement) element; + + System.out.println("Found element: " + typeElement.getQualifiedName().toString()); + element.getAnnotationMirrors().stream() + .filter(annotationMirror -> { + String annotationNames = annotationMirror.getAnnotationType().asElement().getSimpleName().toString(); + return annotationNames.equals("Linked") || annotationNames.equals("Linkages"); + }) + .flatMap(annotationMirror -> annotationMirror.getElementValues().values().stream()) + .map(AnnotationValue::getValue) + .flatMap(o -> { + if (o instanceof List) { + return ((List) o).stream() + .map(AnnotationMirror.class::cast) + .map(AnnotationMirror::getElementValues) + .map(Map::values) + .flatMap(Collection::stream) + .map(AnnotationValue::getValue); + } + return Stream.of(o); + }) + .map(Object::toString) + .map(s -> { + try { + return Class.forName(s); + } catch (Exception e) { + messager.printMessage(Diagnostic.Kind.ERROR, "Could not find class " + s, element); + return null; + } + }) + .filter(Objects::nonNull) + .map(clazz -> { + try { + return (LinkageType) clazz.getDeclaredConstructor().newInstance(); + } catch (Exception e) { + messager.printMessage(Diagnostic.Kind.ERROR, "Could not create instance of " + clazz.getName(), element); + return null; + } + }) + .filter(Objects::nonNull) + .forEach(type -> { + Class clazz = type.getClass(); + if (!type.requirements(typeElement.getSuperclass().toString(), typeElement.getInterfaces().stream().map(TypeMirror::toString).collect(Collectors.toSet()), typeElement)) { + return; + } + + if (alreadyGenerated.add(clazz)) { + runMethod.addLine("if (type == " + clazz.getTypeName() + ".class) {"); + runMethod.addLine(" run" + clazz.getSimpleName() + "();"); + runMethod.addLine("}"); + } + + MethodBuilder method = methods.computeIfAbsent(clazz, t -> { + MethodBuilder methodBuilder = new MethodBuilder("run" + t.getSimpleName(), "void"); + methodBuilder.setPrivate(true); + buildPlan.addMethod(methodBuilder); + return methodBuilder; + }); + specialElements(typeElement, buildPlan, method::addLine, () -> { + type.generateCode(buildPlan, method, getElement(typeElement, neededFields), typeElement); + }); + }); + } + + BufferedWriter bufferedWriter = new BufferedWriter(writer); + buildPlan.write(bufferedWriter); + bufferedWriter.close(); + return true; + } + + private String getElement(TypeElement typeElement, Map neededFields) { + if (neededFields.containsKey(typeElement.getQualifiedName().toString())) { + return typeElement.getSimpleName().toString() + "()"; + } + return "new " + typeElement.getQualifiedName().toString() + "()"; + } + + private void specialElements(TypeElement typeElement, BuildPlan buildPlan, Consumer stringConsumer, Runnable inner) { + MinVersion minVersion = typeElement.getAnnotation(MinVersion.class); + MaxVersion maxVersion = typeElement.getAnnotation(MaxVersion.class); + EventMode eventMode = typeElement.getAnnotation(EventMode.class); + DiscordMode discordMode = typeElement.getAnnotation(DiscordMode.class); + PluginCheck[] pluginChecks = typeElement.getAnnotationsByType(PluginCheck.class); + if (context == LinkageType.Context.SPIGOT) { + errorOnNonNull(typeElement, eventMode, discordMode); + List checks = new ArrayList<>(); + if (minVersion != null) { + buildPlan.addImport("de.steamwar.core.Core"); + checks.add("Core.getVersion() >= " + minVersion.value()); + } + if (maxVersion != null) { + buildPlan.addImport("de.steamwar.core.Core"); + checks.add("Core.getVersion() < " + maxVersion.value()); + } + if (pluginChecks.length != 0) { + buildPlan.addImport("org.bukkit.Bukkit"); + Arrays.stream(pluginChecks).map(pluginCheck -> { + return "Bukkit.getPluginManager().getPlugin(\"" + pluginCheck.value() + "\") " + (pluginCheck.has() == PluginCheck.Has.THIS ? "!" : "=") + "= null"; + }).forEach(checks::add); + } + if (!checks.isEmpty()) stringConsumer.accept("if (" + String.join(" && ", checks) + ") {"); + inner.run(); + if (!checks.isEmpty()) stringConsumer.accept("}"); + } else { + errorOnNonNull(typeElement, minVersion, maxVersion); + List checks = new ArrayList<>(); + if (eventMode != null) { + buildPlan.addImport("de.steamwar.bungeecore.BungeeCore"); + checks.add(eventMode.value().getPrefix() + "BungeeCore.EVENT_MODE"); + } + if (discordMode != null) { + buildPlan.addImport("de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig"); + checks.add("SteamwarDiscordBotConfig.loaded"); + } + if (pluginChecks.length != 0) { + buildPlan.addImport("net.md_5.bungee.BungeeCord"); + Arrays.stream(pluginChecks).map(pluginCheck -> { + return "BungeeCord.getPluginManager().getPlugin(\"" + pluginCheck.value() + "\") " + (pluginCheck.has() == PluginCheck.Has.THIS ? "!" : "=") + "= null"; + }).forEach(checks::add); + } + if (!checks.isEmpty()) stringConsumer.accept("if (" + String.join(" && ", checks) + ") {"); + inner.run(); + if (!checks.isEmpty()) stringConsumer.accept("}"); + } + } + + private void errorOnNonNull(TypeElement typeElement, Annotation... annotations) { + for (Annotation annotation : annotations) { + if (annotation != null) { + messager.printMessage(Diagnostic.Kind.ERROR, annotation.annotationType().getSimpleName() + " is not supported in " + context.name(), typeElement); + } + } + } +} diff --git a/src/de/steamwar/linkage/LinkageType.java b/src/de/steamwar/linkage/LinkageType.java new file mode 100644 index 0000000..afc37cc --- /dev/null +++ b/src/de/steamwar/linkage/LinkageType.java @@ -0,0 +1,58 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage; + +import de.steamwar.linkage.plan.BuildPlan; +import de.steamwar.linkage.plan.MethodBuilder; + +import javax.lang.model.element.TypeElement; +import java.util.Set; + +public interface LinkageType { + + Context context = LinkageProcessor.getContext(); + default String getPluginMain() { + return LinkageProcessor.getPluginMain(); + } + + enum Context { + BUNGEE, + SPIGOT + } + + default boolean requirements(String superClass, Set interfaces, TypeElement typeElement) { + return true; + } + + default void generateCode(BuildPlan buildPlan, MethodBuilder linkageTypeMethod, String instance, TypeElement typeElement) { + switch (context) { + case BUNGEE: + generateCodeBungee(buildPlan, linkageTypeMethod, instance, typeElement); + break; + case SPIGOT: + generateCodeSpigot(buildPlan, linkageTypeMethod, instance, typeElement); + break; + } + } + default void generateCodeBungee(BuildPlan buildPlan, MethodBuilder linkageTypeMethod, String instance, TypeElement typeElement) { + } + default void generateCodeSpigot(BuildPlan buildPlan, MethodBuilder linkageTypeMethod, String instance, TypeElement typeElement) { + } +} diff --git a/src/de/steamwar/linkage/Linked.java b/src/de/steamwar/linkage/Linked.java new file mode 100644 index 0000000..b352982 --- /dev/null +++ b/src/de/steamwar/linkage/Linked.java @@ -0,0 +1,35 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.SOURCE) +@Target({ElementType.TYPE}) +@Repeatable(Linked.Linkages.class) +public @interface Linked { + Class value(); + + @Retention(RetentionPolicy.SOURCE) + @Target({ElementType.TYPE}) + @interface Linkages { + @SuppressWarnings("unused") Linked[] value() default {}; + } +} diff --git a/src/de/steamwar/linkage/LinkedInstance.java b/src/de/steamwar/linkage/LinkedInstance.java new file mode 100644 index 0000000..9636ba5 --- /dev/null +++ b/src/de/steamwar/linkage/LinkedInstance.java @@ -0,0 +1,30 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.SOURCE) +@Target({ElementType.FIELD}) +public @interface LinkedInstance { +} diff --git a/src/de/steamwar/linkage/MaxVersion.java b/src/de/steamwar/linkage/MaxVersion.java new file mode 100644 index 0000000..589a67f --- /dev/null +++ b/src/de/steamwar/linkage/MaxVersion.java @@ -0,0 +1,32 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@AllowedContexts(LinkageType.Context.SPIGOT) +@Retention(RetentionPolicy.SOURCE) +@Target({ElementType.TYPE}) +public @interface MaxVersion { + int value(); +} diff --git a/src/de/steamwar/linkage/MinVersion.java b/src/de/steamwar/linkage/MinVersion.java new file mode 100644 index 0000000..d897935 --- /dev/null +++ b/src/de/steamwar/linkage/MinVersion.java @@ -0,0 +1,32 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@AllowedContexts(LinkageType.Context.SPIGOT) +@Retention(RetentionPolicy.SOURCE) +@Target({ElementType.TYPE}) +public @interface MinVersion { + int value(); +} diff --git a/src/de/steamwar/linkage/PluginCheck.java b/src/de/steamwar/linkage/PluginCheck.java new file mode 100644 index 0000000..6b9931a --- /dev/null +++ b/src/de/steamwar/linkage/PluginCheck.java @@ -0,0 +1,42 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage; + +import java.lang.annotation.*; + +@AllowedContexts({LinkageType.Context.BUNGEE, LinkageType.Context.SPIGOT}) +@Retention(RetentionPolicy.SOURCE) +@Target({ElementType.TYPE}) +@Repeatable(PluginCheck.PluginChecks.class) +public @interface PluginCheck { + Has has() default Has.THIS; + String value(); + + enum Has { + THIS, + NOT + } + + @Retention(RetentionPolicy.SOURCE) + @Target({ElementType.TYPE}) + @interface PluginChecks { + @SuppressWarnings("unused") PluginCheck[] value() default {}; + } +} diff --git a/src/de/steamwar/linkage/api/Disable.java b/src/de/steamwar/linkage/api/Disable.java new file mode 100644 index 0000000..f09b846 --- /dev/null +++ b/src/de/steamwar/linkage/api/Disable.java @@ -0,0 +1,24 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage.api; + +public interface Disable { + void disable(); +} diff --git a/src/de/steamwar/linkage/api/Enable.java b/src/de/steamwar/linkage/api/Enable.java new file mode 100644 index 0000000..5d516cd --- /dev/null +++ b/src/de/steamwar/linkage/api/Enable.java @@ -0,0 +1,24 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage.api; + +public interface Enable { + void enable(); +} diff --git a/src/de/steamwar/linkage/plan/BuildPlan.java b/src/de/steamwar/linkage/plan/BuildPlan.java new file mode 100644 index 0000000..2fc7b8b --- /dev/null +++ b/src/de/steamwar/linkage/plan/BuildPlan.java @@ -0,0 +1,89 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage.plan; + +import lombok.RequiredArgsConstructor; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.*; + +@RequiredArgsConstructor +public class BuildPlan { + + private final String packageName; + private Set imports = new HashSet<>(); + private final String className; + + private List fieldBuilders = new ArrayList<>(); + private Map methodBuilderMap = new HashMap<>(); + private List staticLines = new ArrayList<>(); + + public void addImport(String importName) { + imports.add(importName); + } + + public void addField(FieldBuilder fieldBuilder) { + fieldBuilders.add(fieldBuilder); + } + + public void addMethod(MethodBuilder methodBuilder) { + methodBuilderMap.put(methodBuilder.getMethodName(), methodBuilder); + } + + public boolean hasMethod(String methodName) { + return methodBuilderMap.containsKey(methodName); + } + + public void addStaticLine(String line) { + staticLines.add(line); + } + + public void write(BufferedWriter writer) throws IOException { + writer.write("package " + packageName + ";\n"); + if (!imports.isEmpty()) { + writer.write("\n"); + for (String importName : imports) { + writer.write("import " + importName + ";\n"); + } + } + writer.write("\n"); + writer.write("public class " + className + " {\n"); + if (!fieldBuilders.isEmpty()) { + for (FieldBuilder fieldBuilder : fieldBuilders) { + fieldBuilder.write(writer); + } + writer.write("\n"); + } + if (!staticLines.isEmpty()) { + writer.write(" static {\n"); + for (String line : staticLines) { + writer.write(" " + line + "\n"); + } + writer.write(" }\n"); + writer.write("\n"); + } + for (MethodBuilder methodBuilder : methodBuilderMap.values()) { + methodBuilder.write(writer); + writer.write("\n"); + } + writer.write("}\n"); + } +} diff --git a/src/de/steamwar/linkage/plan/FieldBuilder.java b/src/de/steamwar/linkage/plan/FieldBuilder.java new file mode 100644 index 0000000..12fa440 --- /dev/null +++ b/src/de/steamwar/linkage/plan/FieldBuilder.java @@ -0,0 +1,44 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage.plan; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.io.BufferedWriter; +import java.io.IOException; + +@RequiredArgsConstructor +@AllArgsConstructor +public class FieldBuilder { + @Getter + private final String type; + private final String name; + private String initializer; + + public String getFieldName() { + return name; + } + + public void write(BufferedWriter writer) throws IOException { + writer.write(" private static " + type + " " + getFieldName() + (initializer == null ? "" : " = " + initializer) + ";\n"); + } +} diff --git a/src/de/steamwar/linkage/plan/MethodBuilder.java b/src/de/steamwar/linkage/plan/MethodBuilder.java new file mode 100644 index 0000000..6a31175 --- /dev/null +++ b/src/de/steamwar/linkage/plan/MethodBuilder.java @@ -0,0 +1,70 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage.plan; + +import lombok.RequiredArgsConstructor; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +@RequiredArgsConstructor +public class MethodBuilder { + + private final String name; + private final String returnType; + private List parameters = new ArrayList<>(); + private List lines = new ArrayList<>(); + private boolean isPrivate = false; + + public void addParameter(ParameterBuilder parameterBuilder) { + parameters.add(parameterBuilder); + } + + public void addLine(String line) { + lines.add(line); + } + + public String getMethodName() { + return name; + } + + public void setPrivate(boolean isPrivate) { + this.isPrivate = isPrivate; + } + + public void write(BufferedWriter writer) throws IOException { + writer.write(" " + (isPrivate ? "private" : "public") + " static " + returnType + " " + getMethodName() + "("); + for (int i = 0; i < parameters.size(); i++) { + parameters.get(i).write(writer); + if (i < parameters.size() - 1) { + writer.write(", "); + } + } + writer.write(") {"); + for (String line : lines) { + writer.write("\n"); + writer.write(" " + line); + } + writer.write("\n"); + writer.write(" }\n"); + } +} diff --git a/src/de/steamwar/linkage/plan/ParameterBuilder.java b/src/de/steamwar/linkage/plan/ParameterBuilder.java new file mode 100644 index 0000000..d88364b --- /dev/null +++ b/src/de/steamwar/linkage/plan/ParameterBuilder.java @@ -0,0 +1,35 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage.plan; + +import lombok.AllArgsConstructor; + +import java.io.BufferedWriter; +import java.io.IOException; + +@AllArgsConstructor +public class ParameterBuilder { + private String type; + private String name; + + public void write(BufferedWriter writer) throws IOException { + writer.write(type + " " + name); + } +} diff --git a/src/de/steamwar/linkage/types/Command.java b/src/de/steamwar/linkage/types/Command.java new file mode 100644 index 0000000..6d6948c --- /dev/null +++ b/src/de/steamwar/linkage/types/Command.java @@ -0,0 +1,45 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage.types; + +import de.steamwar.linkage.LinkageType; +import de.steamwar.linkage.plan.BuildPlan; +import de.steamwar.linkage.plan.MethodBuilder; + +import javax.lang.model.element.TypeElement; +import java.util.Set; + +public class Command implements LinkageType { + + @Override + public boolean requirements(String superClass, Set interfaces, TypeElement typeElement) { + return superClass.equals("de.steamwar.command.SWCommand"); + } + + @Override + public void generateCodeBungee(BuildPlan buildPlan, MethodBuilder linkageTypeMethod, String instance, TypeElement typeElement) { + linkageTypeMethod.addLine(instance + ";"); + } + + @Override + public void generateCodeSpigot(BuildPlan buildPlan, MethodBuilder linkageTypeMethod, String instance, TypeElement typeElement) { + linkageTypeMethod.addLine(instance + ".setMessage(" + getPluginMain() + ".MESSAGE);"); + } +} diff --git a/src/de/steamwar/linkage/types/DisableLink.java b/src/de/steamwar/linkage/types/DisableLink.java new file mode 100644 index 0000000..72f816d --- /dev/null +++ b/src/de/steamwar/linkage/types/DisableLink.java @@ -0,0 +1,40 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage.types; + +import de.steamwar.linkage.LinkageType; +import de.steamwar.linkage.plan.BuildPlan; +import de.steamwar.linkage.plan.MethodBuilder; + +import javax.lang.model.element.TypeElement; +import java.util.Set; + +public class DisableLink implements LinkageType { + + @Override + public boolean requirements(String superClass, Set interfaces, TypeElement typeElement) { + return interfaces.contains("de.steamwar.linkage.api.Disable"); + } + + @Override + public void generateCode(BuildPlan buildPlan, MethodBuilder linkageTypeMethod, String instance, TypeElement typeElement) { + linkageTypeMethod.addLine(instance + ".disable();"); + } +} diff --git a/src/de/steamwar/linkage/types/EnableLink.java b/src/de/steamwar/linkage/types/EnableLink.java new file mode 100644 index 0000000..d7630a4 --- /dev/null +++ b/src/de/steamwar/linkage/types/EnableLink.java @@ -0,0 +1,40 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage.types; + +import de.steamwar.linkage.LinkageType; +import de.steamwar.linkage.plan.BuildPlan; +import de.steamwar.linkage.plan.MethodBuilder; + +import javax.lang.model.element.TypeElement; +import java.util.Set; + +public class EnableLink implements LinkageType { + + @Override + public boolean requirements(String superClass, Set interfaces, TypeElement typeElement) { + return interfaces.contains("de.steamwar.linkage.api.Enable"); + } + + @Override + public void generateCode(BuildPlan buildPlan, MethodBuilder linkageTypeMethod, String instance, TypeElement typeElement) { + linkageTypeMethod.addLine(instance + ".enable();"); + } +} diff --git a/src/de/steamwar/linkage/types/ListenerLink.java b/src/de/steamwar/linkage/types/ListenerLink.java new file mode 100644 index 0000000..5c815c5 --- /dev/null +++ b/src/de/steamwar/linkage/types/ListenerLink.java @@ -0,0 +1,113 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage.types; + +import de.steamwar.linkage.LinkageType; +import de.steamwar.linkage.plan.BuildPlan; +import de.steamwar.linkage.plan.FieldBuilder; +import de.steamwar.linkage.plan.MethodBuilder; +import de.steamwar.linkage.plan.ParameterBuilder; + +import javax.lang.model.element.*; +import javax.lang.model.type.DeclaredType; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class ListenerLink implements LinkageType { + + @Override + public boolean requirements(String superClass, Set interfaces, TypeElement typeElement) { + if (context == Context.BUNGEE) { + return interfaces.contains("net.md_5.bungee.api.plugin.Listener"); + } else { + return interfaces.contains("org.bukkit.event.Listener"); + } + } + + @Override + public void generateCodeBungee(BuildPlan buildPlan, MethodBuilder linkageTypeMethod, String instance, TypeElement typeElement) { + buildPlan.addImport("net.md_5.bungee.api.ProxyServer"); + buildPlan.addImport("de.steamwar.bungeecore.BungeeCore"); + linkageTypeMethod.addLine("ProxyServer.getInstance().getPluginManager().registerListener(BungeeCore.get(), " + instance + ");"); + } + + @Override + public void generateCodeSpigot(BuildPlan buildPlan, MethodBuilder linkageTypeMethod, String instance, TypeElement typeElement) { + Map eventClasses = new HashMap<>(); + Map eventMethods = new HashMap<>(); + + typeElement.getEnclosedElements().stream().filter(e -> e.getKind() == ElementKind.METHOD).map(ExecutableElement.class::cast).filter(e -> { + return e.getAnnotationMirrors().stream().anyMatch(annotationMirror -> { + return annotationMirror.getAnnotationType().asElement().getSimpleName().toString().equals("EventHandler"); + }); + }).forEach(e -> { + TypeElement current = ((TypeElement)((DeclaredType) e.getParameters().get(0).asType()).asElement()); + eventClasses.put(current.getQualifiedName().toString(), current); + eventMethods.put(current, e); + }); + + eventClasses.forEach((s, eventType) -> { + if (buildPlan.hasMethod(s)) return; + buildPlan.addImport("org.bukkit.event.HandlerList"); + buildPlan.addImport("org.bukkit.event.Listener"); + buildPlan.addImport("java.util.function.Consumer"); + buildPlan.addImport("org.bukkit.event.EventPriority"); + buildPlan.addImport("org.bukkit.plugin.RegisteredListener"); + buildPlan.addImport("org.bukkit.plugin.EventExecutor"); + buildPlan.addImport(s); + buildPlan.addField(new FieldBuilder("HandlerList", "handlerList" + eventType.getSimpleName())); + MethodBuilder methodBuilder = new MethodBuilder(eventType.getSimpleName().toString(), "void"); + methodBuilder.addParameter(new ParameterBuilder("Listener", "listener")); + methodBuilder.addParameter(new ParameterBuilder("Consumer<" + eventType.getSimpleName() + ">", "consumer")); + methodBuilder.addParameter(new ParameterBuilder("EventPriority", "eventPriority")); + methodBuilder.addParameter(new ParameterBuilder("boolean", "ignoreCancelled")); + methodBuilder.setPrivate(true); + methodBuilder.addLine("EventExecutor eventExecutor = (l, event) -> {"); + methodBuilder.addLine(" if (event instanceof " + eventType.getSimpleName() + ") {"); + methodBuilder.addLine(" consumer.accept((" + eventType.getSimpleName() + ") event);"); + methodBuilder.addLine(" }"); + methodBuilder.addLine("};"); + methodBuilder.addLine("handlerList" + eventType.getSimpleName() + ".register(new RegisteredListener(listener, eventExecutor, eventPriority, " + getPluginMain() + ".getInstance(), ignoreCancelled));"); + buildPlan.addMethod(methodBuilder); + linkageTypeMethod.addLine("handlerList" + eventType.getSimpleName() + " = " + eventType.getSimpleName() + ".getHandlerList();"); + }); + + buildPlan.addImport(typeElement.getQualifiedName().toString()); + String localInstance = "local" + typeElement.getSimpleName().toString(); + linkageTypeMethod.addLine(typeElement.getSimpleName() + " " + localInstance + " = " + instance + ";"); + eventMethods.forEach((type, executableElement) -> { + AnnotationMirror eventHandler = executableElement.getAnnotationMirrors().stream().filter(annotationMirror -> annotationMirror.getAnnotationType().asElement().getSimpleName().toString().equals("EventHandler")).findFirst().orElse(null); + if (eventHandler == null) { + return; + } + String priority = "NORMAL"; + String ignoreCancelled = "false"; + for (Map.Entry entry : eventHandler.getElementValues().entrySet()) { + if (entry.getKey().getSimpleName().toString().equals("priority")) { + priority = entry.getValue().getValue().toString(); + } else if (entry.getKey().getSimpleName().toString().equals("ignoreCancelled")) { + ignoreCancelled = entry.getValue().getValue().toString(); + } + } + linkageTypeMethod.addLine(type.getSimpleName().toString() + "(" + localInstance + ", " + localInstance + "::" + executableElement.getSimpleName().toString() + ", EventPriority." + priority + ", " + ignoreCancelled + ");"); + }); + } +} diff --git a/src/de/steamwar/linkage/types/Plain.java b/src/de/steamwar/linkage/types/Plain.java new file mode 100644 index 0000000..1890521 --- /dev/null +++ b/src/de/steamwar/linkage/types/Plain.java @@ -0,0 +1,34 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage.types; + +import de.steamwar.linkage.LinkageType; +import de.steamwar.linkage.plan.BuildPlan; +import de.steamwar.linkage.plan.MethodBuilder; + +import javax.lang.model.element.TypeElement; + +public class Plain implements LinkageType { + + @Override + public void generateCode(BuildPlan buildPlan, MethodBuilder linkageTypeMethod, String instance, TypeElement typeElement) { + linkageTypeMethod.addLine(instance + ";"); + } +} diff --git a/src/de/steamwar/linkage/types/UnlinkListener.java b/src/de/steamwar/linkage/types/UnlinkListener.java new file mode 100644 index 0000000..564d567 --- /dev/null +++ b/src/de/steamwar/linkage/types/UnlinkListener.java @@ -0,0 +1,53 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.linkage.types; + +import de.steamwar.linkage.LinkageType; +import de.steamwar.linkage.plan.BuildPlan; +import de.steamwar.linkage.plan.MethodBuilder; + +import javax.lang.model.element.TypeElement; +import java.lang.reflect.Type; +import java.util.Set; + +public class UnlinkListener implements LinkageType { + + @Override + public boolean requirements(String superClass, Set interfaces, TypeElement typeElement) { + if (context == Context.BUNGEE) { + return interfaces.contains("net.md_5.bungee.api.plugin.Listener"); + } else { + return interfaces.contains("org.bukkit.event.Listener"); + } + } + + @Override + public void generateCodeBungee(BuildPlan buildPlan, MethodBuilder linkageTypeMethod, String instance, TypeElement typeElement) { + buildPlan.addImport("net.md_5.bungee.api.ProxyServer"); + buildPlan.addImport("de.steamwar.bungeecore.BungeeCore"); + linkageTypeMethod.addLine("ProxyServer.getInstance().getPluginManager().registerListener(" + instance + ");"); + } + + @Override + public void generateCodeSpigot(BuildPlan buildPlan, MethodBuilder linkageTypeMethod, String instance, TypeElement typeElement) { + buildPlan.addImport("org.bukkit.event.HandlerList"); + linkageTypeMethod.addLine("HandlerList.unregisterAll(" + instance + ");"); + } +}