From 18951fa120ba9b097999167ff9498ef8a16292a5 Mon Sep 17 00:00:00 2001 From: allinkdev <44676012+allinkdev@users.noreply.github.com> Date: Mon, 21 Aug 2023 23:39:50 +0100 Subject: [PATCH] Port to ClassGraph (#30) * Port to ClassGraph * Migrate to Minecrell plugin-yml This allows us to load libraries at runtime instead of using shading & creating massive JAR files. * Fix constructor modifiers of cake command * Fix improper usage of CommandMap --- Cladis/build.gradle | 5 ++ Corvo/build.gradle | 6 ++ Corvo/src/main/resources/plugin.yml | 8 -- Datura/build.gradle | 6 ++ Datura/src/main/resources/plugin.yml | 8 -- Fossil/build.gradle | 6 ++ .../main/java/fns/fossil/cmd/CakeCommand.java | 2 +- Fossil/src/main/resources/plugin.yml | 9 -- Patchwork/build.gradle | 9 +- .../fns/patchwork/command/CommandHandler.java | 86 +++++++++++++------ Patchwork/src/main/resources/plugin.yml | 6 -- README.md | 4 +- build.gradle | 9 +- 13 files changed, 99 insertions(+), 65 deletions(-) delete mode 100644 Corvo/src/main/resources/plugin.yml delete mode 100644 Datura/src/main/resources/plugin.yml delete mode 100644 Fossil/src/main/resources/plugin.yml delete mode 100644 Patchwork/src/main/resources/plugin.yml diff --git a/Cladis/build.gradle b/Cladis/build.gradle index 16166a3..3677b6d 100644 --- a/Cladis/build.gradle +++ b/Cladis/build.gradle @@ -20,6 +20,11 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter' } +bukkit { + main = "fns.cladis.Cladis" + description = "Network Manager integration for the Freedom Network Suite." +} + test { useJUnitPlatform() } \ No newline at end of file diff --git a/Corvo/build.gradle b/Corvo/build.gradle index 609c4f3..72b3792 100644 --- a/Corvo/build.gradle +++ b/Corvo/build.gradle @@ -16,6 +16,12 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter' } +bukkit { + main = "fns.corvo.Corvo" + description = "Services and Listeners for the Freedom Network Suite" + depend = ["Patchwork"] +} + test { useJUnitPlatform() } \ No newline at end of file diff --git a/Corvo/src/main/resources/plugin.yml b/Corvo/src/main/resources/plugin.yml deleted file mode 100644 index db2b827..0000000 --- a/Corvo/src/main/resources/plugin.yml +++ /dev/null @@ -1,8 +0,0 @@ -name: Corvo -main: fns.corvo.Corvo -api-version: 1.20 -version: 1.0.0 -author: TotalFreedom -description: Services and Listeners for the Freedom Network Suite -depend: - - Patchwork \ No newline at end of file diff --git a/Datura/build.gradle b/Datura/build.gradle index 397d84c..a59da29 100644 --- a/Datura/build.gradle +++ b/Datura/build.gradle @@ -16,6 +16,12 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter' } +bukkit { + main = "fns.datura.Datura" + description = "Data Manager for the Freedom Network Suite" + depend = ["Patchwork"] +} + var weight = 2 test { diff --git a/Datura/src/main/resources/plugin.yml b/Datura/src/main/resources/plugin.yml deleted file mode 100644 index a70371e..0000000 --- a/Datura/src/main/resources/plugin.yml +++ /dev/null @@ -1,8 +0,0 @@ -name: Datura -main: fns.datura.Datura -api-version: 1.20 -version: 1.0.0 -author: TotalFreedom -description: Data Manager for the Freedom Network Suite -depend: - - Patchwork \ No newline at end of file diff --git a/Fossil/build.gradle b/Fossil/build.gradle index 609c4f3..c5417fd 100644 --- a/Fossil/build.gradle +++ b/Fossil/build.gradle @@ -16,6 +16,12 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter' } +bukkit { + main = "fns.fossil.Fossil" + description = "The Fun Module for the Freedom Network." + depend = ["Datura", "Patchwork"] +} + test { useJUnitPlatform() } \ No newline at end of file diff --git a/Fossil/src/main/java/fns/fossil/cmd/CakeCommand.java b/Fossil/src/main/java/fns/fossil/cmd/CakeCommand.java index 8959d98..4f2f2e8 100644 --- a/Fossil/src/main/java/fns/fossil/cmd/CakeCommand.java +++ b/Fossil/src/main/java/fns/fossil/cmd/CakeCommand.java @@ -40,7 +40,7 @@ import org.jetbrains.annotations.NotNull; @Permissive(perm = "fossil.cake") public class CakeCommand extends Commander { - protected CakeCommand(final @NotNull JavaPlugin plugin) + public CakeCommand(final @NotNull JavaPlugin plugin) { super(plugin); } diff --git a/Fossil/src/main/resources/plugin.yml b/Fossil/src/main/resources/plugin.yml deleted file mode 100644 index f3212a7..0000000 --- a/Fossil/src/main/resources/plugin.yml +++ /dev/null @@ -1,9 +0,0 @@ -name: Fossil -version: 1.0 -main: fns.fossil.Fossil -api-version: 1.20 -author: TotalFreedom -description: The Fun Module for the Freedom Network. -depend: - - Datura - - Patchwork \ No newline at end of file diff --git a/Patchwork/build.gradle b/Patchwork/build.gradle index 24b6581..9e8ee9d 100644 --- a/Patchwork/build.gradle +++ b/Patchwork/build.gradle @@ -6,14 +6,19 @@ repositories { } dependencies { - api 'io.projectreactor:reactor-core:3.5.4' - api 'org.reflections:reflections:0.10.2' + library 'io.projectreactor:reactor-core:3.5.4' + library 'io.github.classgraph:classgraph:4.8.162' api 'org.slf4j:slf4j-api:1.7.36' testImplementation platform('org.junit:junit-bom:5.9.1') testImplementation 'org.junit.jupiter:junit-jupiter' } +bukkit { + main = "fns.patchwork.base.Patchwork" + description = "The Core of Freedom Network Suite" +} + var weight = 1 test { diff --git a/Patchwork/src/main/java/fns/patchwork/command/CommandHandler.java b/Patchwork/src/main/java/fns/patchwork/command/CommandHandler.java index c0ff38f..f3fbe55 100644 --- a/Patchwork/src/main/java/fns/patchwork/command/CommandHandler.java +++ b/Patchwork/src/main/java/fns/patchwork/command/CommandHandler.java @@ -23,11 +23,17 @@ package fns.patchwork.command; +import java.lang.reflect.InvocationTargetException; import java.util.Objects; + +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ClassInfo; +import io.github.classgraph.ScanResult; import org.bukkit.Bukkit; import org.bukkit.command.CommandMap; import org.bukkit.plugin.java.JavaPlugin; -import org.reflections.Reflections; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; /** * Handles the registration of commands. The plugin which initializes this class should be the plugin that is @@ -41,6 +47,10 @@ public class CommandHandler * This should be the plugin instance which is trying to register the commands. */ private final JavaPlugin plugin; + /** + * The logger instance of the plugin this command handler is registered to. + */ + private final Logger logger; /** * Creates a new command handler. @@ -50,18 +60,40 @@ public class CommandHandler public CommandHandler(final JavaPlugin plugin) { this.plugin = plugin; + this.logger = plugin.getSLF4JLogger(); } - /** - * Registers a command. This method will automatically delegate the command information to the Bukkit API and - * register with the {@link CommandMap}. - * - * @param command The command to register. - * @param The type of the command. - */ - public void registerCommand(final T command) - { - new BukkitDelegate(command).register(Bukkit.getServer().getCommandMap()); + private @Nullable Commander instantiateCommandClass(final ClassInfo commandSubclassInfo) { + final Class genericClass; + + try { + genericClass = commandSubclassInfo.loadClass(); + } catch (IllegalArgumentException e) { + this.logger.error("Failed to load command subclass", e); + return null; + } + + final Class subClass; + + try { + subClass = genericClass.asSubclass(Commander.class); + } catch (ClassCastException e) { + this.logger.error("Failed to cast command class to subtype of commander class", e); + return null; + } + + try { + return subClass.getDeclaredConstructor(JavaPlugin.class).newInstance(this.plugin); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException ignored) { + // + } + + try { + return subClass.getDeclaredConstructor(this.plugin.getClass()).newInstance(this.plugin); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + this.logger.error("Failed to instantiate instance of command class", e); + return null; + } } /** @@ -73,22 +105,20 @@ public class CommandHandler */ public void registerCommands(final Class commandClass) { - final Reflections reflections = new Reflections(commandClass.getPackageName()); - reflections.getSubTypesOf(commandClass) - .stream() - .map(c -> - { - try - { - return c.getDeclaredConstructor(JavaPlugin.class).newInstance(this); - } - catch (ReflectiveOperationException ex) - { - plugin.getSLF4JLogger().error("Unable to register command: " + c.getName(), ex); - return null; - } - }) - .filter(Objects::nonNull) - .forEach(this::registerCommand); + final CommandMap commandMap = Bukkit.getCommandMap(); + + try (final ScanResult scanResult = new ClassGraph() + .ignoreParentClassLoaders() + .overrideClassLoaders(commandClass.getClassLoader(), this.getClass().getClassLoader()) + .enableClassInfo() + .acceptPackages(commandClass.getPackageName()) + .scan()) { + + final String lowercasePluginName = this.plugin.getName().toLowerCase(); + scanResult.getSubclasses(Commander.class).stream() + .map(this::instantiateCommandClass) + .filter(Objects::nonNull) + .forEach(c -> commandMap.register(lowercasePluginName, new BukkitDelegate(c))); + } } } diff --git a/Patchwork/src/main/resources/plugin.yml b/Patchwork/src/main/resources/plugin.yml deleted file mode 100644 index c51a0e3..0000000 --- a/Patchwork/src/main/resources/plugin.yml +++ /dev/null @@ -1,6 +0,0 @@ -name: Patchwork -main: fns.patchwork.base.Patchwork -api-version: 1.20 -version: 1.0.0 -author: TotalFreedom -description: The Core of Freedom Network Suite \ No newline at end of file diff --git a/README.md b/README.md index b37b04a..4baf3b5 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ [Kyori Adventure]: https://github.com/KyoriPowered/adventure "Kyori Adventure" -[Reflections API]: https://github.com/ronmamo/reflections "Reflections API" +[ClassGraph]: https://github.com/classgraph/classgraph "ClassGraph" [TotalFreedomMod]: https://github.com/AtlasMediaGroup/TotalFreedomMod "TotalFreedomMod" @@ -69,7 +69,7 @@ This plugin suite also uses the following libraries: - [SLF4J] for logging - [Paper] for the server implementation - [Kyori Adventure] for chat formatting -- [Reflections API] for reflections +- [ClassGraph] for runtime class searching functionality # Developers diff --git a/build.gradle b/build.gradle index 5c91798..95f739f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,7 @@ plugins { id 'java' id 'java-library' + id 'net.minecrell.plugin-yml.bukkit' version '0.6.0' } group 'me.totalfreedom' @@ -9,6 +10,7 @@ version '1.0.0' subprojects { apply plugin: 'java' apply plugin: 'java-library' + apply plugin: 'net.minecrell.plugin-yml.bukkit' repositories { jcenter() @@ -30,6 +32,11 @@ subprojects { } } + bukkit { + apiVersion = "1.20" + author = "TotalFreedom" + } + dependencies { compileOnly 'me.totalfreedom.scissors:Scissors-API:1.19.4-R0.1-SNAPSHOT' compileOnly 'org.javassist:javassist:3.29.1-GA' @@ -37,7 +44,7 @@ subprojects { compileOnly 'org.apache.commons:commons-collections4:4.2' compileOnly 'com.google.guava:guava:31.1-jre' compileOnly 'com.google.code.gson:gson:2.8.8' - compileOnly 'org.reflections:reflections:0.10.2' + compileOnly 'io.github.classgraph:classgraph:4.8.162' compileOnly 'org.slf4j:slf4j-api:1.7.36' }