From cc9761210135667a5881cfe3bb844ce01fb91ae4 Mon Sep 17 00:00:00 2001 From: Focusvity Date: Sat, 19 Mar 2022 14:33:23 +1100 Subject: [PATCH] Use Google's reflection library to register commands --- .../dev/plex/command/annotation/System.java | 7 ++ .../java/dev/plex/command/impl/AdminCMD.java | 2 + .../java/dev/plex/command/impl/DebugCMD.java | 2 + .../dev/plex/command/impl/DeopAllCMD.java | 2 + .../java/dev/plex/command/impl/DeopCMD.java | 2 + .../java/dev/plex/command/impl/ListCMD.java | 2 + .../java/dev/plex/command/impl/OpAllCMD.java | 2 + .../java/dev/plex/command/impl/OpCMD.java | 2 + .../java/dev/plex/command/impl/RankCMD.java | 2 + .../dev/plex/handlers/CommandHandler.java | 66 +++++++------------ src/main/java/dev/plex/util/PlexUtils.java | 49 ++++++++++++++ 11 files changed, 97 insertions(+), 41 deletions(-) create mode 100644 src/main/java/dev/plex/command/annotation/System.java diff --git a/src/main/java/dev/plex/command/annotation/System.java b/src/main/java/dev/plex/command/annotation/System.java new file mode 100644 index 0000000..fb5343e --- /dev/null +++ b/src/main/java/dev/plex/command/annotation/System.java @@ -0,0 +1,7 @@ +package dev.plex.command.annotation; + +public @interface System +{ + + String value(); +} diff --git a/src/main/java/dev/plex/command/impl/AdminCMD.java b/src/main/java/dev/plex/command/impl/AdminCMD.java index e941a95..69fff27 100644 --- a/src/main/java/dev/plex/command/impl/AdminCMD.java +++ b/src/main/java/dev/plex/command/impl/AdminCMD.java @@ -5,6 +5,7 @@ import dev.plex.cache.DataUtils; import dev.plex.command.PlexCommand; import dev.plex.command.annotation.CommandParameters; import dev.plex.command.annotation.CommandPermissions; +import dev.plex.command.annotation.System; import dev.plex.command.exception.ConsoleOnlyException; import dev.plex.command.exception.PlayerNotFoundException; import dev.plex.command.source.RequiredCommandSource; @@ -27,6 +28,7 @@ import org.jetbrains.annotations.Nullable; @CommandPermissions(level = Rank.OP, source = RequiredCommandSource.ANY) @CommandParameters(name = "admin", usage = "/ | remove | setrank | list>", aliases = "saconfig,slconfig,adminconfig,adminmanage", description = "Manage all admins") +@System("ranks") public class AdminCMD extends PlexCommand { //TODO: Better return messages diff --git a/src/main/java/dev/plex/command/impl/DebugCMD.java b/src/main/java/dev/plex/command/impl/DebugCMD.java index 9b84ae0..6a8d0a0 100644 --- a/src/main/java/dev/plex/command/impl/DebugCMD.java +++ b/src/main/java/dev/plex/command/impl/DebugCMD.java @@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList; import dev.plex.command.PlexCommand; import dev.plex.command.annotation.CommandParameters; import dev.plex.command.annotation.CommandPermissions; +import dev.plex.command.annotation.System; import dev.plex.rank.enums.Rank; import dev.plex.util.PlexLog; import dev.plex.util.PlexUtils; @@ -19,6 +20,7 @@ import org.jetbrains.annotations.Nullable; @CommandParameters(name = "pdebug", description = "Plex's debug command", usage = "/ | gamerules>") @CommandPermissions(level = Rank.EXECUTIVE, permission = "plex.debug") +@System("debug") public class DebugCMD extends PlexCommand { @Override diff --git a/src/main/java/dev/plex/command/impl/DeopAllCMD.java b/src/main/java/dev/plex/command/impl/DeopAllCMD.java index abf2bb9..c3eabcc 100644 --- a/src/main/java/dev/plex/command/impl/DeopAllCMD.java +++ b/src/main/java/dev/plex/command/impl/DeopAllCMD.java @@ -3,6 +3,7 @@ package dev.plex.command.impl; import dev.plex.command.PlexCommand; import dev.plex.command.annotation.CommandParameters; import dev.plex.command.annotation.CommandPermissions; +import dev.plex.command.annotation.System; import dev.plex.rank.enums.Rank; import dev.plex.util.PlexUtils; import net.kyori.adventure.text.Component; @@ -14,6 +15,7 @@ import org.jetbrains.annotations.Nullable; @CommandParameters(name = "deopall", description = "Deop everyone on the server", aliases = "deopa") @CommandPermissions(level = Rank.ADMIN) +@System("ranks") public class DeopAllCMD extends PlexCommand { @Override diff --git a/src/main/java/dev/plex/command/impl/DeopCMD.java b/src/main/java/dev/plex/command/impl/DeopCMD.java index 102f3d4..f9cbdab 100644 --- a/src/main/java/dev/plex/command/impl/DeopCMD.java +++ b/src/main/java/dev/plex/command/impl/DeopCMD.java @@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList; import dev.plex.command.PlexCommand; import dev.plex.command.annotation.CommandParameters; import dev.plex.command.annotation.CommandPermissions; +import dev.plex.command.annotation.System; import dev.plex.rank.enums.Rank; import dev.plex.util.PlexUtils; import java.util.List; @@ -15,6 +16,7 @@ import org.jetbrains.annotations.Nullable; @CommandParameters(name = "deop", description = "Deop a player on the server", usage = "/ ") @CommandPermissions(level = Rank.ADMIN, permission = "plex.deop") +@System("ranks") public class DeopCMD extends PlexCommand { @Override diff --git a/src/main/java/dev/plex/command/impl/ListCMD.java b/src/main/java/dev/plex/command/impl/ListCMD.java index 4f10c9a..43a2035 100644 --- a/src/main/java/dev/plex/command/impl/ListCMD.java +++ b/src/main/java/dev/plex/command/impl/ListCMD.java @@ -4,6 +4,7 @@ import com.google.common.collect.Lists; import dev.plex.command.PlexCommand; import dev.plex.command.annotation.CommandParameters; import dev.plex.command.annotation.CommandPermissions; +import dev.plex.command.annotation.System; import dev.plex.rank.enums.Rank; import java.util.List; import net.kyori.adventure.text.Component; @@ -16,6 +17,7 @@ import org.jetbrains.annotations.Nullable; @CommandParameters(name = "list", description = "Show a list of all online players") @CommandPermissions(level = Rank.OP, permission = "plex.list") +@System("ranks") public class ListCMD extends PlexCommand { @Override diff --git a/src/main/java/dev/plex/command/impl/OpAllCMD.java b/src/main/java/dev/plex/command/impl/OpAllCMD.java index b2c5b82..b5bb69e 100644 --- a/src/main/java/dev/plex/command/impl/OpAllCMD.java +++ b/src/main/java/dev/plex/command/impl/OpAllCMD.java @@ -3,6 +3,7 @@ package dev.plex.command.impl; import dev.plex.command.PlexCommand; import dev.plex.command.annotation.CommandParameters; import dev.plex.command.annotation.CommandPermissions; +import dev.plex.command.annotation.System; import dev.plex.rank.enums.Rank; import dev.plex.util.PlexUtils; import net.kyori.adventure.text.Component; @@ -14,6 +15,7 @@ import org.jetbrains.annotations.Nullable; @CommandParameters(name = "opall", description = "Op everyone on the server", aliases = "opa") @CommandPermissions(level = Rank.ADMIN) +@System("ranks") public class OpAllCMD extends PlexCommand { @Override diff --git a/src/main/java/dev/plex/command/impl/OpCMD.java b/src/main/java/dev/plex/command/impl/OpCMD.java index eb75eae..2940ca3 100644 --- a/src/main/java/dev/plex/command/impl/OpCMD.java +++ b/src/main/java/dev/plex/command/impl/OpCMD.java @@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList; import dev.plex.command.PlexCommand; import dev.plex.command.annotation.CommandParameters; import dev.plex.command.annotation.CommandPermissions; +import dev.plex.command.annotation.System; import dev.plex.rank.enums.Rank; import dev.plex.util.PlexUtils; import java.util.List; @@ -15,6 +16,7 @@ import org.jetbrains.annotations.Nullable; @CommandParameters(name = "op", description = "Op a player on the server", usage = "/ ") @CommandPermissions(level = Rank.OP) +@System("ranks") public class OpCMD extends PlexCommand { @Override diff --git a/src/main/java/dev/plex/command/impl/RankCMD.java b/src/main/java/dev/plex/command/impl/RankCMD.java index 5832d92..8e11bac 100644 --- a/src/main/java/dev/plex/command/impl/RankCMD.java +++ b/src/main/java/dev/plex/command/impl/RankCMD.java @@ -3,6 +3,7 @@ package dev.plex.command.impl; import dev.plex.command.PlexCommand; import dev.plex.command.annotation.CommandParameters; import dev.plex.command.annotation.CommandPermissions; +import dev.plex.command.annotation.System; import dev.plex.command.exception.CommandFailException; import dev.plex.command.source.RequiredCommandSource; import dev.plex.rank.enums.Rank; @@ -14,6 +15,7 @@ import org.jetbrains.annotations.Nullable; @CommandPermissions(level = Rank.OP, permission = "plex.rank", source = RequiredCommandSource.ANY) @CommandParameters(name = "rank", description = "Displays your rank") +@System("ranks") public class RankCMD extends PlexCommand { @Override diff --git a/src/main/java/dev/plex/handlers/CommandHandler.java b/src/main/java/dev/plex/handlers/CommandHandler.java index d2a641e..fae0a40 100644 --- a/src/main/java/dev/plex/handlers/CommandHandler.java +++ b/src/main/java/dev/plex/handlers/CommandHandler.java @@ -3,55 +3,39 @@ package dev.plex.handlers; import com.google.common.collect.Lists; import dev.plex.PlexBase; import dev.plex.command.PlexCommand; -import dev.plex.command.impl.*; +import dev.plex.command.annotation.System; import dev.plex.util.PlexLog; +import dev.plex.util.PlexUtils; +import java.lang.reflect.InvocationTargetException; import java.util.List; +import java.util.Set; -// TODO: Switch to Reflections API public class CommandHandler extends PlexBase { public CommandHandler() { + Set> commandSet = PlexUtils.getClassesBySubType("dev.plex.command.impl", PlexCommand.class); List commands = Lists.newArrayList(); - if (plugin.getSystem().equalsIgnoreCase("ranks")) + + commandSet.forEach(clazz -> { - commands.add(new AdminCMD()); - commands.add(new DeopAllCMD()); - commands.add(new DeopCMD()); - commands.add(new ListCMD()); - commands.add(new OpAllCMD()); - commands.add(new OpCMD()); - commands.add(new RankCMD()); - } - if (plugin.config.getBoolean("debug")) - { - commands.add(new DebugCMD()); - } - commands.add(new AdminChatCMD()); - commands.add(new AdminworldCMD()); - commands.add(new AdventureCMD()); - commands.add(new BanCMD()); - commands.add(new CommandSpyCMD()); - commands.add(new CreativeCMD()); - commands.add(new FlatlandsCMD()); - commands.add(new FreezeCMD()); - commands.add(new KickCMD()); - commands.add(new LocalSpawnCMD()); - commands.add(new LockupCMD()); - commands.add(new MasterbuilderworldCMD()); - commands.add(new MuteCMD()); - commands.add(new NameHistoryCMD()); - commands.add(new PlexCMD()); - commands.add(new PunishmentsCMD()); - commands.add(new RawSayCMD()); - commands.add(new SpectatorCMD()); - commands.add(new SurvivalCMD()); - commands.add(new TagCMD()); - commands.add(new TempbanCMD()); - commands.add(new UnbanCMD()); - commands.add(new UnfreezeCMD()); - commands.add(new UnmuteCMD()); - commands.add(new WorldCMD()); - PlexLog.log(String.format("Registered %s commands!", commands.size())); + try + { + System annotation = clazz.getDeclaredAnnotation(System.class); + if (annotation != null && annotation.value().equalsIgnoreCase(plugin.getSystem())) + { + commands.add(clazz.getConstructor().newInstance()); + return; + } + + commands.add(clazz.getConstructor().newInstance()); + } + catch (InvocationTargetException | InstantiationException | IllegalAccessException | NoSuchMethodException ex) + { + PlexLog.log("Failed to register " + clazz.getSimpleName() + " as a command!"); + } + }); + + PlexLog.log(String.format("Registered %s commands from %s classes!", commands.size(), commandSet.size())); } } diff --git a/src/main/java/dev/plex/util/PlexUtils.java b/src/main/java/dev/plex/util/PlexUtils.java index 03adb43..bf661a6 100644 --- a/src/main/java/dev/plex/util/PlexUtils.java +++ b/src/main/java/dev/plex/util/PlexUtils.java @@ -1,5 +1,7 @@ package dev.plex.util; +import com.google.common.collect.ImmutableSet; +import com.google.common.reflect.ClassPath; import dev.plex.Plex; import dev.plex.PlexBase; import dev.plex.config.Config; @@ -15,12 +17,15 @@ import java.time.LocalDateTime; import java.time.ZoneId; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Random; +import java.util.Set; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; @@ -320,6 +325,50 @@ public class PlexUtils extends PlexBase return UUID.fromString(uuidString); } + @SuppressWarnings("UnstableApiUsage") + public static Set> getClassesFrom(String packageName) + { + Set> classes = new HashSet<>(); + try + { + ClassPath path = ClassPath.from(Plex.class.getClassLoader()); + ImmutableSet infoSet = path.getTopLevelClasses(packageName); + infoSet.forEach(info -> + { + try + { + Class clazz = Class.forName(info.getName()); + classes.add(clazz); + } + catch (ClassNotFoundException ex) + { + PlexLog.error("Unable to find class " + info.getName() + " in " + packageName); + } + }); + } + catch (IOException ex) + { + PlexLog.error("Something went wrong while fetching classes from " + packageName); + throw new RuntimeException(ex); + } + return Collections.unmodifiableSet(classes); + } + + @SuppressWarnings("unchecked") + public static Set> getClassesBySubType(String packageName, Class subType) + { + Set> loadedClasses = getClassesFrom(packageName); + Set> classes = new HashSet<>(); + loadedClasses.forEach(clazz -> + { + if (clazz.getSuperclass() == subType || Arrays.asList(clazz.getInterfaces()).contains(subType)) + { + classes.add((Class)clazz); + } + }); + return Collections.unmodifiableSet(classes); + } + public static int randomNum() { return ThreadLocalRandom.current().nextInt();