Skip to content

Commit

Permalink
feat: add Folia Support (#217)
Browse files Browse the repository at this point in the history
* feat!: initial Folia support - fixes #213

* feat: add Folia plugin management

* chore: amend to review

* chore: suppress unused in deprecated bootstrap
  • Loading branch information
LooFifteen authored Apr 2, 2023
1 parent ab7d62d commit f3a6a0c
Show file tree
Hide file tree
Showing 19 changed files with 789 additions and 14 deletions.
6 changes: 0 additions & 6 deletions annotations/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,4 @@ dependencies {
}

implementation(libs.gson)
}

java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(8))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import dev.hypera.chameleon.annotations.processing.generation.Generator;
import dev.hypera.chameleon.annotations.processing.generation.bukkit.BukkitGenerator;
import dev.hypera.chameleon.annotations.processing.generation.bungeecord.BungeeCordGenerator;
import dev.hypera.chameleon.annotations.processing.generation.folia.FoliaGenerator;
import dev.hypera.chameleon.annotations.processing.generation.minestom.MinestomGenerator;
import dev.hypera.chameleon.annotations.processing.generation.nukkit.NukkitGenerator;
import dev.hypera.chameleon.annotations.processing.generation.sponge.SpongeGenerator;
Expand All @@ -48,7 +49,7 @@
* Chameleon Annotation Processor.
*/
@SupportedAnnotationTypes("dev.hypera.chameleon.annotations.Plugin")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedSourceVersion(SourceVersion.RELEASE_11)
public class ChameleonAnnotationProcessor extends AbstractProcessor {

/**
Expand Down Expand Up @@ -80,6 +81,9 @@ public synchronized boolean process(Set<? extends TypeElement> annotations, Roun
case Platform.BUNGEECORD:
generator = new BungeeCordGenerator();
break;
case Platform.FOLIA:
generator = new FoliaGenerator();
break;
case Platform.MINESTOM:
generator = new MinestomGenerator();
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* This file is a part of the Chameleon Framework, licensed under the MIT License.
*
* Copyright (c) 2021-2023 The Chameleon Framework Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package dev.hypera.chameleon.annotations.processing.generation.folia;

import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import dev.hypera.chameleon.annotations.Plugin;
import dev.hypera.chameleon.annotations.exception.ChameleonAnnotationException;
import dev.hypera.chameleon.annotations.processing.generation.Generator;
import dev.hypera.chameleon.annotations.utils.MapBuilder;
import dev.hypera.chameleon.exception.instantiation.ChameleonInstantiationException;
import dev.hypera.chameleon.platform.Platform;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Objects;
import java.util.logging.Level;
import java.util.stream.Collectors;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.tools.StandardLocation;
import org.jetbrains.annotations.NotNull;
import org.yaml.snakeyaml.Yaml;

/**
* Bukkit plugin main class and 'paper-plugin.yml' description file generator.
*/
public final class FoliaGenerator extends Generator {

private static final @NotNull String DESCRIPTION_FILE = "paper-plugin.yml";

/**
* Generate Bukkit plugin main class and 'plugin.yml' description file.
*
* @param data {@link Plugin} data
* @param plugin Chameleon plugin main class
* @param env Processing environment
*
* @throws ChameleonAnnotationException if something goes wrong while creating the files.
*/
@Override
public void generate(@NotNull Plugin data, @NotNull TypeElement plugin, @NotNull ProcessingEnvironment env) throws ChameleonAnnotationException {
MethodSpec constructorSpec = MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC)
.beginControlFlow("try")
.addStatement(createPluginData(data))
.addStatement("this.$N = $T.createFoliaBootstrap($T.class, this, $N).load()", CHAMELEON_VAR, clazz("dev.hypera.chameleon.platform.folia", "FoliaChameleon"), plugin, "pluginData")
.nextControlFlow("catch ($T ex)", ChameleonInstantiationException.class)
.addStatement("getLogger().log($T.SEVERE, \"An error occurred while loading Chameleon\", $N)", Level.class, "ex")
.addStatement("throw new $T($N)", clazz("dev.hypera.chameleon.exception", "ChameleonRuntimeException"), "ex")
.endControlFlow()
.build();

MethodSpec enableSpec = MethodSpec.methodBuilder("onEnable")
.addAnnotation(Override.class).addModifiers(Modifier.PUBLIC)
.addStatement("this.$N.onEnable()", CHAMELEON_VAR).build();

MethodSpec disableSpec = MethodSpec.methodBuilder("onDisable")
.addAnnotation(Override.class).addModifiers(Modifier.PUBLIC)
.addStatement("this.$N.onDisable()", CHAMELEON_VAR).build();

TypeSpec foliaMainClassSpec = TypeSpec.classBuilder(plugin.getSimpleName() + "Folia")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.superclass(clazz("org.bukkit.plugin.java", "JavaPlugin"))
.addField(FieldSpec.builder(clazz("dev.hypera.chameleon.platform.folia", "FoliaChameleon"), CHAMELEON_VAR, Modifier.PRIVATE).build())
.addMethod(constructorSpec)
.addMethod(enableSpec)
.addMethod(disableSpec)
.build();

String packageName = Objects.requireNonNull((PackageElement) plugin.getEnclosingElement()).getQualifiedName().toString();
if (packageName.endsWith("core") || packageName.endsWith("common")) {
packageName = packageName.substring(0, packageName.lastIndexOf("."));
}
packageName = packageName + ".platform.folia";

try {
JavaFile.builder(packageName, foliaMainClassSpec).indent(INDENT).build().writeTo(env.getFiler());
generateDescriptionFile(data, plugin, env, packageName);
} catch (IOException ex) {
throw new ChameleonAnnotationException("Failed to write main class or description file", ex);
}
}

private void generateDescriptionFile(@NotNull Plugin data, @NotNull TypeElement plugin, @NotNull ProcessingEnvironment env, @NotNull String packageName) throws IOException {
try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(env.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", DESCRIPTION_FILE).toUri()))) {
new Yaml().dump(new MapBuilder<String, Object>().add("name", data.name().isEmpty() ? data.id() : data.name())
.add("main", packageName + "." + plugin.getSimpleName() + "Folia")
.add("version", data.version())
.add("api-version", "1.19")
.add("author", data.authors().length > 0 ? String.join(", ", data.authors()) : "Unknown")
.add("authors", data.authors())
.add("website", data.url())
.add("dependencies", Arrays.stream(data.dependencies())
.filter(d -> (d.platforms().length == 0 || Arrays.asList(d.platforms()).contains(Platform.FOLIA)))
.map(d -> new MapBuilder<String, Object>()
.add("name", d.name())
.add("required", !d.soft())
).collect(Collectors.toList()))
.add("description", data.description())
.add("folia-supported", "true"), writer);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public interface Platform {

@NotNull String BUKKIT = "Bukkit";
@NotNull String BUNGEECORD = "BungeeCord";
@NotNull String FOLIA = "Folia";
@NotNull String MINESTOM = "Minestom";
@NotNull String NUKKIT = "Nukkit";
@NotNull String SPONGE = "Sponge";
Expand Down
2 changes: 1 addition & 1 deletion build-logic/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@ dependencies {

java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(8))
languageVersion.set(JavaLanguageVersion.of(11))
}
}
8 changes: 7 additions & 1 deletion build-logic/src/main/kotlin/chameleon.base.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,16 @@ plugins {
}

val libs = extensions.getByType<VersionCatalogsExtension>().named("libs")
val requires17 = setOf(
"chameleon-example",
"chameleon-platform-folia",
"chameleon-platform-minestom",
"chameleon-platform-sponge",
)

indra {
javaVersions {
if (project.name.contains("minestom") || project.name.contains("sponge") || project.name.contains("example")) {
if (project.name in requires17) {
target(17)
testWith(17)
} else {
Expand Down
6 changes: 4 additions & 2 deletions example/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,15 @@ plugins {
*/
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(8))
languageVersion.set(JavaLanguageVersion.of(11))
targetCompatibility = JavaVersion.VERSION_17
}
}

repositories {
maven("https://oss.sonatype.org/content/repositories/snapshots/") // Required for BungeeCord support
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") // Required for Bukkit support
maven("https://papermc.io/repo/repository/maven-public/") // Required for Folia support
// maven("https://jitpack.io/") // Required for Minestom support
maven("https://repo.spongepowered.org/maven/") // Required for Minestom/Sponge support
maven("https://repo.opencollab.dev/main/") // Required for Nukkit support
Expand All @@ -60,6 +61,7 @@ dependencies {
implementation(project(":chameleon-api")) // dev.hypera:chameleon-api
implementation(project(":chameleon-platform-bukkit")) // dev.hypera:chameleon-platform-bukkit
implementation(project(":chameleon-platform-bungeecord")) // dev.hypera:chameleon-platform-bungeecord
implementation(project(":chameleon-platform-folia")) // dev.hypera:chameleon-platform-folia
implementation(project(":chameleon-platform-nukkit")) // dev.hypera:chameleon-platform-nukkit
implementation(project(":chameleon-platform-minestom")) // dev.hypera:chameleon-platform-minestom
implementation(project(":chameleon-platform-velocity")) // dev.hypera:chameleon-platform-velocity
Expand All @@ -79,7 +81,7 @@ tasks {
mergeServiceFiles()

/* IMPORTANT: Relocate all dependencies to avoid conflicts */
relocate("dev.hypera.chameleon", "dev.hypera.chameleon.example.lib.chameleon")
//relocate("dev.hypera.chameleon", "dev.hypera.chameleon.example.lib.chameleon") // Cannot relocate because example is in this package.
relocate("net.kyori", "dev.hypera.chameleon.example.lib.kyori")
relocate("com.google.gson", "dev.hypera.chameleon.example.lib.gson")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import dev.hypera.chameleon.example.event.ExampleCustomEvent;
import dev.hypera.chameleon.logger.ChameleonLogger;
import dev.hypera.chameleon.platform.Platform;
import dev.hypera.chameleon.platform.PlatformPlugin;
import dev.hypera.chameleon.scheduler.Schedule;
import dev.hypera.chameleon.scheduler.Task;
import java.time.Duration;
Expand All @@ -57,12 +58,13 @@
@Dependency(
name = "LuckPerms",
soft = true,
platforms = { Platform.BUKKIT }
platforms = { Platform.BUKKIT, Platform.FOLIA }
)
},
platforms = {
Platform.BUKKIT,
Platform.BUNGEECORD,
Platform.FOLIA,
Platform.MINESTOM,
Platform.NUKKIT,
Platform.SPONGE,
Expand Down Expand Up @@ -130,6 +132,11 @@ public void onEnable() {
this.logger.info("This task will run twice!")
).delay(Schedule.seconds(2)).repeat(Schedule.seconds(5)).cancelAfter(2).build());

/* Plugin Management */
for (PlatformPlugin plugin : chameleon.getPluginManager().getPlugins()) {
this.logger.info("Found plugin %s v%s", plugin.getName(), plugin.getVersion());
}

this.logger.info(
"Successfully started ChameleonExample plugin, took %s ms.",
Duration.between(start, Instant.now()).toMillis()
Expand Down
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ adventure-platform = "4.3.0"
# Platforms
platform-bukkit = "1.19-R0.1-SNAPSHOT"
platform-bungeecord = "1.19-R0.1-SNAPSHOT"
platform-folia = "1.19.4-R0.1-SNAPSHOT"
platform-minestom = "aebf72de90"
platform-nukkit = "1.0-SNAPSHOT"
platform-sponge = "9.0.0"
Expand Down Expand Up @@ -54,6 +55,7 @@ adventure-platform-bungeecord = { module = "net.kyori:adventure-platform-bungeec
# Platforms
platform-bukkit = { module = "org.spigotmc:spigot-api", version.ref = "platform-bukkit" }
platform-bungeecord = { module = "net.md-5:bungeecord-api", version.ref = "platform-bungeecord" }
platform-folia = { module = "dev.folia:folia-api", version.ref = "platform-folia" }
platform-minestom = { module = "com.github.Minestom:Minestom", version.ref = "platform-minestom" }
platform-nukkit = { module = "cn.nukkit:nukkit", version.ref = "platform-nukkit" }
platform-sponge = { module = "org.spongepowered:spongeapi", version.ref = "platform-sponge" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,16 @@
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.ApiStatus.Internal;
import org.jetbrains.annotations.ApiStatus.NonExtendable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
* Bukkit Chameleon implementation.
* Not final to allow Folia implementation to extend this class.
*/
public final class BukkitChameleon extends Chameleon {
@NonExtendable
public class BukkitChameleon extends Chameleon {

private final @NotNull JavaPlugin plugin;
private final @NotNull BukkitPlatform platform = new BukkitPlatform();
Expand All @@ -65,7 +68,8 @@ public final class BukkitChameleon extends Chameleon {
private @Nullable ChameleonAudienceProvider audienceProvider;

@Internal
BukkitChameleon(@NotNull Class<? extends ChameleonPlugin> chameleonPlugin, @NotNull Collection<ChameleonExtension<?>> extensions, @NotNull JavaPlugin bukkitPlugin, @NotNull ChameleonPluginData pluginData) throws ChameleonInstantiationException {
// Protected to allow Folia to extend this class.
protected BukkitChameleon(@NotNull Class<? extends ChameleonPlugin> chameleonPlugin, @NotNull Collection<ChameleonExtension<?>> extensions, @NotNull JavaPlugin bukkitPlugin, @NotNull ChameleonPluginData pluginData) throws ChameleonInstantiationException {
super(chameleonPlugin, extensions, pluginData, new ChameleonJavaLogger(bukkitPlugin.getLogger()));
this.plugin = bukkitPlugin;
}
Expand Down
37 changes: 37 additions & 0 deletions platform-folia/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* This file is a part of the Chameleon Framework, licensed under the MIT License.
*
* Copyright (c) 2021-2023 The Chameleon Framework Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
plugins {
id("chameleon.common")
id("java-library")
}

repositories {
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
maven("https://repo.papermc.io/repository/maven-public/")
}

dependencies {
api(project(":chameleon-platform-bukkit"))
compileOnlyApi(libs.platform.folia)
}
Loading

0 comments on commit f3a6a0c

Please sign in to comment.