|
| 1 | +/* |
| 2 | + * This file is a part of the Chameleon Framework, licensed under the MIT License. |
| 3 | + * |
| 4 | + * Copyright (c) 2021-2023 The Chameleon Framework Authors. |
| 5 | + * |
| 6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 7 | + * of this software and associated documentation files (the "Software"), to deal |
| 8 | + * in the Software without restriction, including without limitation the rights |
| 9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 10 | + * copies of the Software, and to permit persons to whom the Software is |
| 11 | + * furnished to do so, subject to the following conditions: |
| 12 | + * |
| 13 | + * The above copyright notice and this permission notice shall be included in all |
| 14 | + * copies or substantial portions of the Software. |
| 15 | + * |
| 16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 19 | + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 22 | + * SOFTWARE. |
| 23 | + */ |
| 24 | +package dev.hypera.chameleon.annotations.processing.generation.folia; |
| 25 | + |
| 26 | +import com.squareup.javapoet.FieldSpec; |
| 27 | +import com.squareup.javapoet.JavaFile; |
| 28 | +import com.squareup.javapoet.MethodSpec; |
| 29 | +import com.squareup.javapoet.TypeSpec; |
| 30 | +import dev.hypera.chameleon.annotations.Plugin; |
| 31 | +import dev.hypera.chameleon.annotations.exception.ChameleonAnnotationException; |
| 32 | +import dev.hypera.chameleon.annotations.processing.generation.Generator; |
| 33 | +import dev.hypera.chameleon.annotations.utils.MapBuilder; |
| 34 | +import dev.hypera.chameleon.exception.instantiation.ChameleonInstantiationException; |
| 35 | +import dev.hypera.chameleon.platform.Platform; |
| 36 | +import java.io.BufferedWriter; |
| 37 | +import java.io.IOException; |
| 38 | +import java.nio.file.Files; |
| 39 | +import java.nio.file.Paths; |
| 40 | +import java.util.Arrays; |
| 41 | +import java.util.Objects; |
| 42 | +import java.util.logging.Level; |
| 43 | +import java.util.stream.Collectors; |
| 44 | +import javax.annotation.processing.ProcessingEnvironment; |
| 45 | +import javax.lang.model.element.Modifier; |
| 46 | +import javax.lang.model.element.PackageElement; |
| 47 | +import javax.lang.model.element.TypeElement; |
| 48 | +import javax.tools.StandardLocation; |
| 49 | +import org.jetbrains.annotations.NotNull; |
| 50 | +import org.yaml.snakeyaml.Yaml; |
| 51 | + |
| 52 | +/** |
| 53 | + * Bukkit plugin main class and 'paper-plugin.yml' description file generator. |
| 54 | + */ |
| 55 | +public final class FoliaGenerator extends Generator { |
| 56 | + |
| 57 | + private static final @NotNull String DESCRIPTION_FILE = "paper-plugin.yml"; |
| 58 | + |
| 59 | + /** |
| 60 | + * Generate Bukkit plugin main class and 'plugin.yml' description file. |
| 61 | + * |
| 62 | + * @param data {@link Plugin} data |
| 63 | + * @param plugin Chameleon plugin main class |
| 64 | + * @param env Processing environment |
| 65 | + * |
| 66 | + * @throws ChameleonAnnotationException if something goes wrong while creating the files. |
| 67 | + */ |
| 68 | + @Override |
| 69 | + public void generate(@NotNull Plugin data, @NotNull TypeElement plugin, @NotNull ProcessingEnvironment env) throws ChameleonAnnotationException { |
| 70 | + MethodSpec constructorSpec = MethodSpec.constructorBuilder() |
| 71 | + .addModifiers(Modifier.PUBLIC) |
| 72 | + .beginControlFlow("try") |
| 73 | + .addStatement(createPluginData(data)) |
| 74 | + .addStatement("this.$N = $T.createFoliaBootstrap($T.class, this, $N).load()", CHAMELEON_VAR, clazz("dev.hypera.chameleon.platform.folia", "FoliaChameleon"), plugin, "pluginData") |
| 75 | + .nextControlFlow("catch ($T ex)", ChameleonInstantiationException.class) |
| 76 | + .addStatement("getLogger().log($T.SEVERE, \"An error occurred while loading Chameleon\", $N)", Level.class, "ex") |
| 77 | + .addStatement("throw new $T($N)", clazz("dev.hypera.chameleon.exception", "ChameleonRuntimeException"), "ex") |
| 78 | + .endControlFlow() |
| 79 | + .build(); |
| 80 | + |
| 81 | + MethodSpec enableSpec = MethodSpec.methodBuilder("onEnable") |
| 82 | + .addAnnotation(Override.class).addModifiers(Modifier.PUBLIC) |
| 83 | + .addStatement("this.$N.onEnable()", CHAMELEON_VAR).build(); |
| 84 | + |
| 85 | + MethodSpec disableSpec = MethodSpec.methodBuilder("onDisable") |
| 86 | + .addAnnotation(Override.class).addModifiers(Modifier.PUBLIC) |
| 87 | + .addStatement("this.$N.onDisable()", CHAMELEON_VAR).build(); |
| 88 | + |
| 89 | + TypeSpec foliaMainClassSpec = TypeSpec.classBuilder(plugin.getSimpleName() + "Folia") |
| 90 | + .addModifiers(Modifier.PUBLIC, Modifier.FINAL) |
| 91 | + .superclass(clazz("org.bukkit.plugin.java", "JavaPlugin")) |
| 92 | + .addField(FieldSpec.builder(clazz("dev.hypera.chameleon.platform.folia", "FoliaChameleon"), CHAMELEON_VAR, Modifier.PRIVATE).build()) |
| 93 | + .addMethod(constructorSpec) |
| 94 | + .addMethod(enableSpec) |
| 95 | + .addMethod(disableSpec) |
| 96 | + .build(); |
| 97 | + |
| 98 | + String packageName = Objects.requireNonNull((PackageElement) plugin.getEnclosingElement()).getQualifiedName().toString(); |
| 99 | + if (packageName.endsWith("core") || packageName.endsWith("common")) { |
| 100 | + packageName = packageName.substring(0, packageName.lastIndexOf(".")); |
| 101 | + } |
| 102 | + packageName = packageName + ".platform.folia"; |
| 103 | + |
| 104 | + try { |
| 105 | + JavaFile.builder(packageName, foliaMainClassSpec).indent(INDENT).build().writeTo(env.getFiler()); |
| 106 | + generateDescriptionFile(data, plugin, env, packageName); |
| 107 | + } catch (IOException ex) { |
| 108 | + throw new ChameleonAnnotationException("Failed to write main class or description file", ex); |
| 109 | + } |
| 110 | + } |
| 111 | + |
| 112 | + private void generateDescriptionFile(@NotNull Plugin data, @NotNull TypeElement plugin, @NotNull ProcessingEnvironment env, @NotNull String packageName) throws IOException { |
| 113 | + try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(env.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", DESCRIPTION_FILE).toUri()))) { |
| 114 | + new Yaml().dump(new MapBuilder<String, Object>().add("name", data.name().isEmpty() ? data.id() : data.name()) |
| 115 | + .add("main", packageName + "." + plugin.getSimpleName() + "Folia") |
| 116 | + .add("version", data.version()) |
| 117 | + .add("api-version", "1.19") |
| 118 | + .add("author", data.authors().length > 0 ? String.join(", ", data.authors()) : "Unknown") |
| 119 | + .add("authors", data.authors()) |
| 120 | + .add("website", data.url()) |
| 121 | + .add("dependencies", Arrays.stream(data.dependencies()) |
| 122 | + .filter(d -> (d.platforms().length == 0 || Arrays.asList(d.platforms()).contains(Platform.FOLIA))) |
| 123 | + .map(d -> new MapBuilder<String, Object>() |
| 124 | + .add("name", d.name()) |
| 125 | + .add("required", !d.soft()) |
| 126 | + ).collect(Collectors.toList())) |
| 127 | + .add("description", data.description()) |
| 128 | + .add("folia-supported", "true"), writer); |
| 129 | + } |
| 130 | + } |
| 131 | + |
| 132 | +} |
0 commit comments