Use Google's reflection library to register commands

This commit is contained in:
Focusvity 2022-03-19 14:33:23 +11:00
parent 6a569bb638
commit cc97612101
No known key found for this signature in database
GPG Key ID: 85AD157561ABE94B
11 changed files with 97 additions and 41 deletions

View File

@ -0,0 +1,7 @@
package dev.plex.command.annotation;
public @interface System
{
String value();
}

View File

@ -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 = "/<command> <add <player> | remove <player> | setrank <player> <rank> | list>", aliases = "saconfig,slconfig,adminconfig,adminmanage", description = "Manage all admins")
@System("ranks")
public class AdminCMD extends PlexCommand
{
//TODO: Better return messages

View File

@ -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 = "/<command> <redis-reset <player> | gamerules>")
@CommandPermissions(level = Rank.EXECUTIVE, permission = "plex.debug")
@System("debug")
public class DebugCMD extends PlexCommand
{
@Override

View File

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

View File

@ -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 = "/<command> <player>")
@CommandPermissions(level = Rank.ADMIN, permission = "plex.deop")
@System("ranks")
public class DeopCMD extends PlexCommand
{
@Override

View File

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

View File

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

View File

@ -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 = "/<command> <player>")
@CommandPermissions(level = Rank.OP)
@System("ranks")
public class OpCMD extends PlexCommand
{
@Override

View File

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

View File

@ -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<Class<? extends PlexCommand>> commandSet = PlexUtils.getClassesBySubType("dev.plex.command.impl", PlexCommand.class);
List<PlexCommand> 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()));
}
}

View File

@ -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<Class<?>> getClassesFrom(String packageName)
{
Set<Class<?>> classes = new HashSet<>();
try
{
ClassPath path = ClassPath.from(Plex.class.getClassLoader());
ImmutableSet<ClassPath.ClassInfo> 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 <T> Set<Class<? extends T>> getClassesBySubType(String packageName, Class<T> subType)
{
Set<Class<?>> loadedClasses = getClassesFrom(packageName);
Set<Class<? extends T>> classes = new HashSet<>();
loadedClasses.forEach(clazz ->
{
if (clazz.getSuperclass() == subType || Arrays.asList(clazz.getInterfaces()).contains(subType))
{
classes.add((Class<? extends T>)clazz);
}
});
return Collections.unmodifiableSet(classes);
}
public static int randomNum()
{
return ThreadLocalRandom.current().nextInt();