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
This commit is contained in:
allinkdev 2023-08-21 23:39:50 +01:00 committed by GitHub
parent bec93a9142
commit 18951fa120
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 99 additions and 65 deletions

View File

@ -20,6 +20,11 @@ dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.junit.jupiter:junit-jupiter'
} }
bukkit {
main = "fns.cladis.Cladis"
description = "Network Manager integration for the Freedom Network Suite."
}
test { test {
useJUnitPlatform() useJUnitPlatform()
} }

View File

@ -16,6 +16,12 @@ dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.junit.jupiter:junit-jupiter'
} }
bukkit {
main = "fns.corvo.Corvo"
description = "Services and Listeners for the Freedom Network Suite"
depend = ["Patchwork"]
}
test { test {
useJUnitPlatform() useJUnitPlatform()
} }

View File

@ -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

View File

@ -16,6 +16,12 @@ dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.junit.jupiter:junit-jupiter'
} }
bukkit {
main = "fns.datura.Datura"
description = "Data Manager for the Freedom Network Suite"
depend = ["Patchwork"]
}
var weight = 2 var weight = 2
test { test {

View File

@ -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

View File

@ -16,6 +16,12 @@ dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.junit.jupiter:junit-jupiter'
} }
bukkit {
main = "fns.fossil.Fossil"
description = "The Fun Module for the Freedom Network."
depend = ["Datura", "Patchwork"]
}
test { test {
useJUnitPlatform() useJUnitPlatform()
} }

View File

@ -40,7 +40,7 @@ import org.jetbrains.annotations.NotNull;
@Permissive(perm = "fossil.cake") @Permissive(perm = "fossil.cake")
public class CakeCommand extends Commander public class CakeCommand extends Commander
{ {
protected CakeCommand(final @NotNull JavaPlugin plugin) public CakeCommand(final @NotNull JavaPlugin plugin)
{ {
super(plugin); super(plugin);
} }

View File

@ -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

View File

@ -6,14 +6,19 @@ repositories {
} }
dependencies { dependencies {
api 'io.projectreactor:reactor-core:3.5.4' library 'io.projectreactor:reactor-core:3.5.4'
api 'org.reflections:reflections:0.10.2' library 'io.github.classgraph:classgraph:4.8.162'
api 'org.slf4j:slf4j-api:1.7.36' api 'org.slf4j:slf4j-api:1.7.36'
testImplementation platform('org.junit:junit-bom:5.9.1') testImplementation platform('org.junit:junit-bom:5.9.1')
testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.junit.jupiter:junit-jupiter'
} }
bukkit {
main = "fns.patchwork.base.Patchwork"
description = "The Core of Freedom Network Suite"
}
var weight = 1 var weight = 1
test { test {

View File

@ -23,11 +23,17 @@
package fns.patchwork.command; package fns.patchwork.command;
import java.lang.reflect.InvocationTargetException;
import java.util.Objects; 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.Bukkit;
import org.bukkit.command.CommandMap; import org.bukkit.command.CommandMap;
import org.bukkit.plugin.java.JavaPlugin; 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 * 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. * This should be the plugin instance which is trying to register the commands.
*/ */
private final JavaPlugin plugin; 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. * Creates a new command handler.
@ -50,18 +60,40 @@ public class CommandHandler
public CommandHandler(final JavaPlugin plugin) public CommandHandler(final JavaPlugin plugin)
{ {
this.plugin = plugin; this.plugin = plugin;
this.logger = plugin.getSLF4JLogger();
} }
/** private @Nullable Commander instantiateCommandClass(final ClassInfo commandSubclassInfo) {
* Registers a command. This method will automatically delegate the command information to the Bukkit API and final Class<?> genericClass;
* register with the {@link CommandMap}.
* try {
* @param command The command to register. genericClass = commandSubclassInfo.loadClass();
* @param <T> The type of the command. } catch (IllegalArgumentException e) {
*/ this.logger.error("Failed to load command subclass", e);
public <T extends Commander> void registerCommand(final T command) return null;
{ }
new BukkitDelegate(command).register(Bukkit.getServer().getCommandMap());
final Class<? extends Commander> 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 <T extends Commander> void registerCommands(final Class<T> commandClass) public <T extends Commander> void registerCommands(final Class<T> commandClass)
{ {
final Reflections reflections = new Reflections(commandClass.getPackageName()); final CommandMap commandMap = Bukkit.getCommandMap();
reflections.getSubTypesOf(commandClass)
.stream() try (final ScanResult scanResult = new ClassGraph()
.map(c -> .ignoreParentClassLoaders()
{ .overrideClassLoaders(commandClass.getClassLoader(), this.getClass().getClassLoader())
try .enableClassInfo()
{ .acceptPackages(commandClass.getPackageName())
return c.getDeclaredConstructor(JavaPlugin.class).newInstance(this); .scan()) {
}
catch (ReflectiveOperationException ex) final String lowercasePluginName = this.plugin.getName().toLowerCase();
{ scanResult.getSubclasses(Commander.class).stream()
plugin.getSLF4JLogger().error("Unable to register command: " + c.getName(), ex); .map(this::instantiateCommandClass)
return null;
}
})
.filter(Objects::nonNull) .filter(Objects::nonNull)
.forEach(this::registerCommand); .forEach(c -> commandMap.register(lowercasePluginName, new BukkitDelegate(c)));
}
} }
} }

View File

@ -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

View File

@ -12,7 +12,7 @@
[Kyori Adventure]: https://github.com/KyoriPowered/adventure "Kyori Adventure" [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" [TotalFreedomMod]: https://github.com/AtlasMediaGroup/TotalFreedomMod "TotalFreedomMod"
@ -69,7 +69,7 @@ This plugin suite also uses the following libraries:
- [SLF4J] for logging - [SLF4J] for logging
- [Paper] for the server implementation - [Paper] for the server implementation
- [Kyori Adventure] for chat formatting - [Kyori Adventure] for chat formatting
- [Reflections API] for reflections - [ClassGraph] for runtime class searching functionality
# Developers # Developers

View File

@ -1,6 +1,7 @@
plugins { plugins {
id 'java' id 'java'
id 'java-library' id 'java-library'
id 'net.minecrell.plugin-yml.bukkit' version '0.6.0'
} }
group 'me.totalfreedom' group 'me.totalfreedom'
@ -9,6 +10,7 @@ version '1.0.0'
subprojects { subprojects {
apply plugin: 'java' apply plugin: 'java'
apply plugin: 'java-library' apply plugin: 'java-library'
apply plugin: 'net.minecrell.plugin-yml.bukkit'
repositories { repositories {
jcenter() jcenter()
@ -30,6 +32,11 @@ subprojects {
} }
} }
bukkit {
apiVersion = "1.20"
author = "TotalFreedom"
}
dependencies { dependencies {
compileOnly 'me.totalfreedom.scissors:Scissors-API:1.19.4-R0.1-SNAPSHOT' compileOnly 'me.totalfreedom.scissors:Scissors-API:1.19.4-R0.1-SNAPSHOT'
compileOnly 'org.javassist:javassist:3.29.1-GA' compileOnly 'org.javassist:javassist:3.29.1-GA'
@ -37,7 +44,7 @@ subprojects {
compileOnly 'org.apache.commons:commons-collections4:4.2' compileOnly 'org.apache.commons:commons-collections4:4.2'
compileOnly 'com.google.guava:guava:31.1-jre' compileOnly 'com.google.guava:guava:31.1-jre'
compileOnly 'com.google.code.gson:gson:2.8.8' 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' compileOnly 'org.slf4j:slf4j-api:1.7.36'
} }