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
13 changed files with 99 additions and 65 deletions

View File

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

View File

@ -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 <T> The type of the command.
*/
public <T extends Commander> 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<? 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)
{
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)));
}
}
}

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