diff options
Diffstat (limited to 'src/main/java/cc/polyfrost/oneconfig/utils')
21 files changed, 298 insertions, 196 deletions
diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/GuiUtils.java b/src/main/java/cc/polyfrost/oneconfig/utils/GuiUtils.java index c6afb00..29c26fb 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/GuiUtils.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/GuiUtils.java @@ -3,20 +3,21 @@ package cc.polyfrost.oneconfig.utils; import cc.polyfrost.oneconfig.events.EventManager; import cc.polyfrost.oneconfig.events.event.RenderEvent; import cc.polyfrost.oneconfig.events.event.Stage; -import cc.polyfrost.oneconfig.libs.eventbus.Subscribe; -import cc.polyfrost.oneconfig.libs.universal.UMinecraft; -import cc.polyfrost.oneconfig.libs.universal.UScreen; +import gg.essential.universal.UMinecraft; +import gg.essential.universal.UScreen; +import me.kbrewster.eventbus.Subscribe; import net.minecraft.client.gui.GuiScreen; /** * A class containing utility methods for working with GuiScreens. */ public final class GuiUtils { + private static long time = -1L; + private static long deltaTime = 17L; + static { EventManager.INSTANCE.register(new GuiUtils()); } - private static long time = -1L; - private static long deltaTime = 17L; /** * Displays a screen after a tick, preventing mouse sync issues. @@ -27,7 +28,9 @@ public final class GuiUtils { new TickDelay(() -> UScreen.displayScreen(screen), 1); } - /** Close the current open GUI screen. */ + /** + * Close the current open GUI screen. + */ public static void closeScreen() { UScreen.displayScreen(null); } @@ -35,8 +38,8 @@ public final class GuiUtils { /** * Gets the delta time (in milliseconds) between frames. * <p><b> - * Not to be confused with Minecraft deltaTicks / renderPartialTicks, which can be gotten via - * {@link cc.polyfrost.oneconfig.events.event.TimerUpdateEvent} + * Not to be confused with Minecraft deltaTicks / renderPartialTicks, which can be gotten via + * {@link cc.polyfrost.oneconfig.events.event.TimerUpdateEvent} * </b></p> * * @return the delta time. diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/InputUtils.java b/src/main/java/cc/polyfrost/oneconfig/utils/InputUtils.java index 0ba4c00..7ec5ee5 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/InputUtils.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/InputUtils.java @@ -1,14 +1,14 @@ package cc.polyfrost.oneconfig.utils; import cc.polyfrost.oneconfig.gui.OneConfigGui; -import cc.polyfrost.oneconfig.libs.universal.UResolution; +import gg.essential.universal.UResolution; import org.lwjgl.input.Mouse; /** * Various utility methods for input. * <p> * All values returned from this class are not scaled to Minecraft's GUI scale. - * For scaled values, see {@link cc.polyfrost.oneconfig.libs.universal.UMouse}. + * For scaled values, see {@link gg.essential.universal.UMouse}. * </p> */ public final class InputUtils { @@ -28,10 +28,10 @@ public final class InputUtils { /** * Checks whether the mouse is currently over a specific region and clicked. * - * @param x the x position of the region - * @param y the y position of the region - * @param width the width of the region - * @param height the height of the region + * @param x the x position of the region + * @param y the y position of the region + * @param width the width of the region + * @param height the height of the region * @param ignoreBlock if true, will ignore {@link InputUtils#blockClicks(boolean)} * @return true if the mouse is clicked and is over the region, false if not * @see InputUtils#isAreaHovered(int, int, int, int) @@ -43,9 +43,9 @@ public final class InputUtils { /** * Checks whether the mouse is currently over a specific region and clicked. * - * @param x the x position of the region - * @param y the y position of the region - * @param width the width of the region + * @param x the x position of the region + * @param y the y position of the region + * @param width the width of the region * @param height the height of the region * @return true if the mouse is clicked and is over the region, false if not * @see InputUtils#isAreaClicked(int, int, int, int, boolean) @@ -78,7 +78,7 @@ public final class InputUtils { * Gets the current mouse X position. * <p> * All values returned from this class are not scaled to Minecraft's GUI scale. - * For scaled values, see {@link cc.polyfrost.oneconfig.libs.universal.UMouse}. + * For scaled values, see {@link gg.essential.universal.UMouse}. * </p> * * @return the current mouse X position @@ -92,7 +92,7 @@ public final class InputUtils { * Gets the current mouse Y position. * <p> * All values returned from this class are not scaled to Minecraft's GUI scale. - * For scaled values, see {@link cc.polyfrost.oneconfig.libs.universal.UMouse}. + * For scaled values, see {@link gg.essential.universal.UMouse}. * </p> * * @return the current mouse Y position @@ -111,6 +111,7 @@ public final class InputUtils { /** * Whether clicks are blocked + * * @return true if clicks are blocked, false if not */ public static boolean isBlockingClicks() { diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/JsonUtils.java b/src/main/java/cc/polyfrost/oneconfig/utils/JsonUtils.java index 67881e9..320b630 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/JsonUtils.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/JsonUtils.java @@ -16,7 +16,7 @@ public final class JsonUtils { /** * Parses a string into a {@link JsonElement}. * - * @param string The string to parse. + * @param string The string to parse. * @param catchExceptions Whether to catch exceptions. * @return The {@link JsonElement}. * @see JsonParser#parse(String) diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/Multithreading.java b/src/main/java/cc/polyfrost/oneconfig/utils/Multithreading.java index 518d699..745ded8 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/Multithreading.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/Multithreading.java @@ -52,7 +52,7 @@ public class Multithreading { * Schedules the runnable to run asynchronously after the specified delay. * * @param runnable The runnable to run. - * @param delay The delay before the runnable is run. + * @param delay The delay before the runnable is run. * @param timeUnit The {@link TimeUnit} of the delay. * @see Multithreading#submitScheduled(Runnable, long, TimeUnit) */ @@ -64,7 +64,7 @@ public class Multithreading { * Submits the Runnable to the executor after a delay, making it run asynchronously. * * @param runnable The runnable to run. - * @param delay The delay before the runnable is run. + * @param delay The delay before the runnable is run. * @param timeUnit The {@link TimeUnit} of the delay. * @return The future representing the submitted runnable. * @see ScheduledExecutorService#schedule(Runnable, long, TimeUnit) diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/NetworkUtils.java b/src/main/java/cc/polyfrost/oneconfig/utils/NetworkUtils.java index 767f36f..5578e1e 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/NetworkUtils.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/NetworkUtils.java @@ -1,7 +1,7 @@ package cc.polyfrost.oneconfig.utils; -import cc.polyfrost.oneconfig.libs.universal.UDesktop; import com.google.gson.JsonElement; +import gg.essential.universal.UDesktop; import org.apache.commons.io.IOUtils; import java.io.*; @@ -18,9 +18,10 @@ public final class NetworkUtils { /** * Gets the contents of a URL as a String. - * @param url The URL to read. + * + * @param url The URL to read. * @param userAgent The user agent to use. - * @param timeout The timeout in milliseconds. + * @param timeout The timeout in milliseconds. * @param useCaches Whether to use caches. * @return The contents of the URL. */ @@ -47,9 +48,9 @@ public final class NetworkUtils { /** * Gets the contents of a URL as a JsonElement. * - * @param url The URL to read. + * @param url The URL to read. * @param userAgent The user agent to use. - * @param timeout The timeout in milliseconds. + * @param timeout The timeout in milliseconds. * @param useCaches Whether to use caches. * @return The contents of the URL. * @see NetworkUtils#getString(String, String, int, boolean) @@ -72,10 +73,11 @@ public final class NetworkUtils { /** * Downloads a file from a URL. - * @param url The URL to download from. - * @param file The file to download to. + * + * @param url The URL to download from. + * @param file The file to download to. * @param userAgent The user agent to use. - * @param timeout The timeout in milliseconds. + * @param timeout The timeout in milliseconds. * @param useCaches Whether to use caches. * @return Whether the download was successful. */ @@ -92,7 +94,8 @@ public final class NetworkUtils { /** * Downloads a file from a URL. - * @param url The URL to download from. + * + * @param url The URL to download from. * @param file The file to download to. * @return Whether the download was successful. * @see NetworkUtils#downloadFile(String, File, String, int, boolean) @@ -103,6 +106,7 @@ public final class NetworkUtils { /** * Gets the SHA-256 hash of a file. + * * @param file The file to hash. * @return The SHA-256 hash of the file. */ diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/OneUIScreen.java b/src/main/java/cc/polyfrost/oneconfig/utils/OneUIScreen.java index 6aaec37..dac995d 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/OneUIScreen.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/OneUIScreen.java @@ -1,8 +1,8 @@ package cc.polyfrost.oneconfig.utils; -import cc.polyfrost.oneconfig.libs.universal.UMatrixStack; -import cc.polyfrost.oneconfig.libs.universal.UScreen; import cc.polyfrost.oneconfig.lwjgl.RenderManager; +import gg.essential.universal.UMatrixStack; +import gg.essential.universal.UScreen; import net.minecraft.client.gui.GuiScreen; import org.jetbrains.annotations.NotNull; import org.lwjgl.input.Mouse; diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/TextUtils.java b/src/main/java/cc/polyfrost/oneconfig/utils/TextUtils.java index 4fa5125..df37aae 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/TextUtils.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/TextUtils.java @@ -13,11 +13,12 @@ public final class TextUtils { /** * Wraps a string into an array of lines. - * @param vg The NanoVG context. - * @param text The text to wrap. + * + * @param vg The NanoVG context. + * @param text The text to wrap. * @param maxWidth The maximum width of each line. * @param fontSize The font size. - * @param font The font to use. + * @param font The font to use. * @return The array of lines. */ public static ArrayList<String> wrapText(long vg, String text, float maxWidth, float fontSize, Fonts font) { @@ -26,11 +27,12 @@ public final class TextUtils { /** * Wraps a string into an array of lines. - * @param vg The NanoVG context. - * @param text The text to wrap. + * + * @param vg The NanoVG context. + * @param text The text to wrap. * @param maxWidth The maximum width of each line. * @param fontSize The font size. - * @param font The font to use. + * @param font The font to use. * @return The array of lines. */ public static ArrayList<String> wrapText(long vg, String text, float maxWidth, float fontSize, Font font) { diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/TickDelay.java b/src/main/java/cc/polyfrost/oneconfig/utils/TickDelay.java index 35b7b8b..7b6be2c 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/TickDelay.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/TickDelay.java @@ -3,14 +3,14 @@ package cc.polyfrost.oneconfig.utils; import cc.polyfrost.oneconfig.events.EventManager; import cc.polyfrost.oneconfig.events.event.Stage; import cc.polyfrost.oneconfig.events.event.TickEvent; -import cc.polyfrost.oneconfig.libs.eventbus.Subscribe; +import me.kbrewster.eventbus.Subscribe; /** * Schedules a Runnable to be called after a certain amount of ticks. */ public class TickDelay { - private int delay; private final Runnable function; + private int delay; public TickDelay(Runnable functionName, int ticks) { EventManager.INSTANCE.register(this); diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/commands/CommandHelper.java b/src/main/java/cc/polyfrost/oneconfig/utils/commands/CommandHelper.java deleted file mode 100644 index 3e7b7ea..0000000 --- a/src/main/java/cc/polyfrost/oneconfig/utils/commands/CommandHelper.java +++ /dev/null @@ -1,19 +0,0 @@ -package cc.polyfrost.oneconfig.utils.commands; - -/** - * A helper class for commands. - * Extend this class and run {@link CommandHelper#preload()} (which does nothing, - * just makes loading look nicer lol) - * - * @see cc.polyfrost.oneconfig.utils.commands.annotations.Command - */ -public abstract class CommandHelper { - - public CommandHelper() { - CommandManager.INSTANCE.registerCommand(this); - } - - public void preload() { - - } -} diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/commands/CommandManager.java b/src/main/java/cc/polyfrost/oneconfig/utils/commands/CommandManager.java index 913ee73..32bbf5d 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/commands/CommandManager.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/commands/CommandManager.java @@ -1,12 +1,14 @@ package cc.polyfrost.oneconfig.utils.commands; -import cc.polyfrost.oneconfig.libs.universal.ChatColor; -import cc.polyfrost.oneconfig.libs.universal.UChat; -import cc.polyfrost.oneconfig.utils.commands.annotations.*; +import cc.polyfrost.oneconfig.utils.commands.annotations.Command; +import cc.polyfrost.oneconfig.utils.commands.annotations.Greedy; +import cc.polyfrost.oneconfig.utils.commands.annotations.Main; +import cc.polyfrost.oneconfig.utils.commands.annotations.SubCommand; import cc.polyfrost.oneconfig.utils.commands.arguments.*; +import gg.essential.universal.ChatColor; +import gg.essential.universal.UChat; import net.minecraft.command.CommandBase; import net.minecraft.command.ICommandSender; -import net.minecraft.util.BlockPos; import net.minecraftforge.client.ClientCommandHandler; import java.lang.reflect.InvocationTargetException; @@ -14,7 +16,6 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Parameter; import java.util.*; -import java.util.stream.Collectors; /** * Handles the registration of OneConfig commands. @@ -23,9 +24,9 @@ import java.util.stream.Collectors; */ public class CommandManager { public static final CommandManager INSTANCE = new CommandManager(); - private final HashMap<Class<?>, ArgumentParser<?>> parsers = new HashMap<>(); private static final String NOT_FOUND_TEXT = "Command not found! Type /@ROOT_COMMAND@ help for help."; private static final String METHOD_RUN_ERROR = "Error while running @ROOT_COMMAND@ method! Please report this to the developer."; + private final HashMap<Class<?>, ArgumentParser<?>> parsers = new HashMap<>(); private CommandManager() { addParser(new StringParser()); @@ -61,22 +62,19 @@ public class CommandManager { /** * Registers the provided command. * - * @param command The command to register. + * @param clazz The command to register as a class. */ - public void registerCommand(Object command) { - Class<?> clazz = command.getClass(); + public void registerCommand(Class<?> clazz) { if (clazz.isAnnotationPresent(Command.class)) { final Command annotation = clazz.getAnnotation(Command.class); - ArrayList<InternalCommand.InternalCommandInvoker> mainCommandFuncs = new ArrayList<>(); + final InternalCommand root = new InternalCommand(annotation.value(), annotation.aliases(), annotation.description().trim().isEmpty() ? "Main command for " + annotation.value() : annotation.description(), null); for (Method method : clazz.getDeclaredMethods()) { if (method.isAnnotationPresent(Main.class) && method.getParameterCount() == 0) { - mainCommandFuncs.add(new InternalCommand.InternalCommandInvoker(annotation.value(), annotation.aliases(), method)); + root.invokers.add(new InternalCommand.InternalCommandInvoker(annotation.value(), annotation.aliases(), method, root)); break; } } - - final InternalCommand root = new InternalCommand(annotation.value(), annotation.aliases(), annotation.description().trim().isEmpty() ? "Main command for " + annotation.value() : annotation.description(), mainCommandFuncs); addToInvokers(clazz.getDeclaredClasses(), root); ClientCommandHandler.instance.registerCommand(new CommandBase() { @Override @@ -94,26 +92,57 @@ public class CommandManager { if (args.length == 0) { if (!root.invokers.isEmpty()) { try { - root.invokers.stream().findFirst().get().method.invoke(null); + root.invokers.get(0).method.invoke(null); } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException | ExceptionInInitializerError e) { + e.printStackTrace(); UChat.chat(ChatColor.RED.toString() + ChatColor.BOLD + METHOD_RUN_ERROR); } } } else { if (annotation.helpCommand() && args[0].equalsIgnoreCase("help")) { - UChat.chat(sendHelpCommand(root)); + //UChat.chat(sendHelpCommand(root)); } else { + List<InternalCommand.InternalCommandInvoker> commands = new ArrayList<>(); + int depth = 0; for (InternalCommand command : root.children) { - String result = runThroughCommands(command, 0, args); - if (result == null) { - return; - } else if (!result.equals(NOT_FOUND_TEXT)) { - UChat.chat(ChatColor.RED.toString() + ChatColor.BOLD + result.replace("@ROOT_COMMAND@", getCommandName())); - return; + int newDepth = loopThroughCommands(commands, 0, command, args, true); + if (newDepth != -1) { + depth = newDepth; + break; + } + } + System.out.println(depth); + System.out.println(commands); + if (commands.isEmpty()) { + UChat.chat(ChatColor.RED.toString() + ChatColor.BOLD + NOT_FOUND_TEXT.replace("@ROOT_COMMAND@", annotation.value())); + } else { + List<CustomError> errors = new ArrayList<>(); + for (InternalCommand.InternalCommandInvoker invoker : commands) { + try { + List<Object> params = getParametersForInvoker(invoker, depth, args); + if (params.size() == 1) { + Object first = params.get(0); + if (first instanceof CustomError) { + errors.add((CustomError) first); + continue; + } + } + invoker.method.invoke(null, params.toArray()); + return; + } catch (Exception e) { + e.printStackTrace(); + UChat.chat(ChatColor.RED.toString() + ChatColor.BOLD + METHOD_RUN_ERROR); + return; + } + } + if (!errors.isEmpty()) { + UChat.chat(ChatColor.RED.toString() + ChatColor.BOLD + "Multiple errors occurred:"); + for (CustomError error : errors) { + UChat.chat(" " + ChatColor.RED + ChatColor.BOLD + error.message); + } } } - UChat.chat(ChatColor.RED.toString() + ChatColor.BOLD + NOT_FOUND_TEXT.replace("@ROOT_COMMAND@", getCommandName())); } } } @@ -122,146 +151,142 @@ public class CommandManager { public int getRequiredPermissionLevel() { return -1; } - }); - } - } - private String sendHelpCommand(InternalCommand root) { - StringBuilder builder = new StringBuilder(); - builder.append(ChatColor.GOLD.toString() + "Help for " + ChatColor.BOLD + root.name + ChatColor.RESET + ChatColor.GOLD + ":\n"); - builder.append("\n"); - for (InternalCommand command : root.children) { - runThroughCommandsHelp(root.name, root, builder); - } - builder.append("\n" + ChatColor.GOLD + "Aliases: " + ChatColor.BOLD); - int index = 0; - for (String alias : root.aliases) { - ++index; - builder.append(alias + (index < root.aliases.length ? ", " : "")); - } - builder.append("\n"); - return builder.toString(); - } + /*/ + @Override + public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) { + List<InternalCommand.InternalCommandInvoker> commands = new ArrayList<>(); + int depth = 0; + for (InternalCommand command : root.children) { + int newDepth = loopThroughCommands(commands, 0, command, args, false); + if (newDepth != -1) { + depth = newDepth; + break; + } + } + System.out.println(depth); + System.out.println(commands); + if (!commands.isEmpty()) { + for (InternalCommand.InternalCommandInvoker invoker : commands) { + try { + List<Object> params = getParametersForInvoker(invoker, depth, args); + invoker.method.invoke(null, params.toArray()); + return; + } catch (Exception ignored) { - private void runThroughCommandsHelp(String append, InternalCommand command, StringBuilder builder) { - for (InternalCommand.InternalCommandInvoker invoker : command.invokers) { - builder.append("\n" + ChatColor.GOLD + "/" + append + " " + command.name); - for (Parameter parameter : invoker.method.getParameters()) { - String name = parameter.getName(); - if (parameter.isAnnotationPresent(Name.class)) { - name = parameter.getAnnotation(Name.class).value(); + } + } + } } - builder.append(" <" + name + ">"); - } - if (!command.description.trim().isEmpty()) { - builder.append(": " + ChatColor.BOLD + command.description); - } - } - for (InternalCommand subCommand : command.children) { - runThroughCommandsHelp(append + " " + command.name, subCommand, builder); + + */ + }); } } - private String runThroughCommands(InternalCommand command, int layer, String[] args) { - int newLayer = layer + 1; - if (command.isEqual(args[layer]) && !command.invokers.isEmpty()) { - Set<InternalCommand.InternalCommandInvoker> invokers = command.invokers.stream().filter(invoker -> newLayer == args.length - invoker.parameterTypes.length).sorted(Comparator.comparingInt((a) -> a.method.getAnnotation(Main.class).priority())).collect(Collectors.toSet()); - if (!invokers.isEmpty()) { - for (InternalCommand.InternalCommandInvoker invoker : invokers) { - try { - String a = tryInvoker(invoker, newLayer, args); - if (a == null) { - return null; - } else if (a.contains(METHOD_RUN_ERROR)) { - return a; - } - } catch (Exception ignored) { - - } - } - } else { - for (InternalCommand subCommand : command.children) { - String result = runThroughCommands(subCommand, newLayer, args); - if (result == null) { - return null; - } else if (!result.equals(NOT_FOUND_TEXT)) { - return result; + private List<Object> getParametersForInvoker(InternalCommand.InternalCommandInvoker invoker, int depth, String[] args) { + List<Object> parameters = new ArrayList<>(); + int processed = depth; + int currentParam = 0; + while (processed < args.length) { + Parameter param = invoker.method.getParameters()[currentParam]; + if (param.isAnnotationPresent(Greedy.class) && currentParam + 1 != invoker.method.getParameterCount()) { + return Collections.singletonList(new CustomError("Parsing failed: Greedy parameter must be the last one.")); + } + ArgumentParser<?> parser = parsers.get(param.getType()); + if (parser == null) { + return Collections.singletonList(new CustomError("No parser for " + invoker.method.getParameterTypes()[currentParam].getSimpleName() + "! Please report this to the mod author.")); + } + try { + Arguments arguments = new Arguments(Arrays.copyOfRange(args, processed, args.length), param.isAnnotationPresent(Greedy.class)); + try { + Object a = parser.parse(arguments); + if (a != null) { + parameters.add(a); + processed += arguments.getPosition(); + currentParam++; + } else { + return Collections.singletonList(new CustomError("Failed to parse " + param.getType().getSimpleName() + "! Please report this to the mod author.")); } + } catch (Exception e) { + return Collections.singletonList(new CustomError("A " + e.getClass().getSimpleName() + " has occured while try to parse " + param.getType().getSimpleName() + "! Please report this to the mod author.")); } + } catch (Exception e) { + return Collections.singletonList(new CustomError("A " + e.getClass().getSimpleName() + " has occured while try to parse " + param.getType().getSimpleName() + "! Please report this to the mod author.")); } } - return NOT_FOUND_TEXT; + return parameters; } - private String tryInvoker(InternalCommand.InternalCommandInvoker invoker, int newLayer, String[] args) { - try { - ArrayList<Object> params = new ArrayList<>(); - int processed = newLayer; - int currentParam = 0; - while (processed < args.length) { - Parameter param = invoker.method.getParameters()[currentParam]; - if (param.isAnnotationPresent(Greedy.class) && currentParam + 1 != invoker.method.getParameterCount()) { - return "Parsing failed: Greedy parameter must be the last one."; + private int loopThroughCommands(List<InternalCommand.InternalCommandInvoker> commands, int depth, InternalCommand command, String[] args, boolean checkParams) { + int nextDepth = depth + 1; + if (command.isEqual(args[depth])) { + for (InternalCommand child : command.children) { + if (args.length > nextDepth && child.isEqual(args[nextDepth])) { + int result = loopThroughCommands(commands, nextDepth, child, args, checkParams); + if (result != -1) { + return result; + } } - ArgumentParser<?> parser = parsers.get(param.getType()); - if (parser == null) { - return "No parser for " + invoker.method.getParameterTypes()[currentParam].getSimpleName() + "! Please report this to the mod author."; + } + boolean added = false; + for (InternalCommand.InternalCommandInvoker invoker : command.invokers) { + if (!checkParams || args.length - nextDepth == invoker.method.getParameterCount()) { + commands.add(invoker); + added = true; } - try { - Arguments arguments = new Arguments(Arrays.copyOfRange(args, processed, args.length), param.isAnnotationPresent(Greedy.class)); - try { - Object a = parser.parse(arguments); - if (a != null) { - params.add(a); - processed += arguments.getPosition(); - currentParam++; - } else { - return "Failed to parse " + param.getType().getSimpleName() + "! Please report this to the mod author."; - } - } catch (Exception e) { - return "A " + e.getClass().getSimpleName() + " has occured while try to parse " + param.getType().getSimpleName() + "! Please report this to the mod author."; - } - } catch (Exception e) { - return "A " + e.getClass().getSimpleName() + " has occured while try to parse " + param.getType().getSimpleName() + "! Please report this to the mod author."; + } + if (added) { + return nextDepth; + } + } else { + for (InternalCommand child : command.children) { + int childDepth = loopThroughCommands(commands, nextDepth, child, args, checkParams); + if (childDepth != -1) { + return childDepth; } } - invoker.method.invoke(null, params.toArray()); - return null; - } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException | - ExceptionInInitializerError e) { - return ChatColor.RED.toString() + ChatColor.BOLD + METHOD_RUN_ERROR; } + return -1; } private void addToInvokers(Class<?>[] classes, InternalCommand parent) { for (Class<?> clazz : classes) { if (clazz.isAnnotationPresent(SubCommand.class)) { SubCommand annotation = clazz.getAnnotation(SubCommand.class); - ArrayList<InternalCommand.InternalCommandInvoker> mainMethods = new ArrayList<>(); + InternalCommand command = new InternalCommand(annotation.value(), annotation.aliases(), annotation.description(), parent); for (Method method : clazz.getDeclaredMethods()) { if (method.isAnnotationPresent(Main.class)) { - mainMethods.add(new InternalCommand.InternalCommandInvoker(annotation.value(), annotation.aliases(), method)); + command.invokers.add(new InternalCommand.InternalCommandInvoker(annotation.value(), annotation.aliases(), method, command)); } } - InternalCommand command = new InternalCommand(annotation.value(), annotation.aliases(), annotation.description(), mainMethods); parent.children.add(command); addToInvokers(clazz.getDeclaredClasses(), command); } } } + private static class CustomError { + public String message; + + public CustomError(String message) { + this.message = message; + } + } + private static class InternalCommand { public final String name; public final String[] aliases; public final String description; - public final ArrayList<InternalCommandInvoker> invokers; + public final ArrayList<InternalCommandInvoker> invokers = new ArrayList<>(); + public final InternalCommand parent; public final ArrayList<InternalCommand> children = new ArrayList<>(); - public InternalCommand(String name, String[] aliases, String description, ArrayList<InternalCommandInvoker> invokers) { + public InternalCommand(String name, String[] aliases, String description, InternalCommand parent) { this.name = name; this.aliases = aliases; - this.invokers = invokers; this.description = description; + this.parent = parent; } public boolean isEqual(String name) { @@ -277,13 +302,24 @@ public class CommandManager { return false; } + @Override + public String toString() { + return "InternalCommand{" + + "name='" + name + '\'' + + ", aliases=" + Arrays.toString(aliases) + + ", description='" + description + '\'' + + ", invokers=" + invokers + + '}'; + } + public static class InternalCommandInvoker { public final String name; public final String[] aliases; public final Method method; public final Parameter[] parameterTypes; + public final InternalCommand parent; - public InternalCommandInvoker(String name, String[] aliases, Method method) { + public InternalCommandInvoker(String name, String[] aliases, Method method, InternalCommand parent) { if (!Modifier.isStatic(method.getModifiers())) { throw new IllegalArgumentException("All command methods must be static!"); } @@ -291,10 +327,21 @@ public class CommandManager { this.aliases = aliases; this.method = method; this.parameterTypes = method.getParameters().clone(); + this.parent = parent; if (Modifier.isPrivate(method.getModifiers()) || Modifier.isProtected(method.getModifiers())) { method.setAccessible(true); } } + + @Override + public String toString() { + return "InternalCommandInvoker{" + + "name='" + name + '\'' + + ", aliases=" + Arrays.toString(aliases) + + ", method=" + method + + ", parameterTypes=" + Arrays.toString(parameterTypes) + + '}'; + } } } } diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/commands/annotations/Command.java b/src/main/java/cc/polyfrost/oneconfig/utils/commands/annotations/Command.java index b1a4ce5..deec7f1 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/commands/annotations/Command.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/commands/annotations/Command.java @@ -1,6 +1,5 @@ package cc.polyfrost.oneconfig.utils.commands.annotations; -import cc.polyfrost.oneconfig.utils.commands.CommandHelper; import cc.polyfrost.oneconfig.utils.commands.CommandManager; import cc.polyfrost.oneconfig.utils.commands.arguments.ArgumentParser; @@ -72,9 +71,8 @@ import java.lang.annotation.Target; * } * }</pre> * </p> - * - * To register commands, either extend {@link CommandHelper} and run {@link CommandHelper#preload()} (which does nothing, - * just makes loading look nicer lol), or use {@link CommandManager#registerCommand(Object)}. + * <p> + * To register commands, use {@link CommandManager#registerCommand(Class)}. * * <p> * Note: if you're viewing this in IntelliJ or just see the @literal tag everywhere, please ignore that. diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/commands/annotations/Main.java b/src/main/java/cc/polyfrost/oneconfig/utils/commands/annotations/Main.java index 3c105c7..9b49fb4 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/commands/annotations/Main.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/commands/annotations/Main.java @@ -16,5 +16,6 @@ import java.lang.annotation.Target; @Target({ElementType.METHOD}) public @interface Main { String description() default ""; + int priority() default 1000; } diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/commands/annotations/Name.java b/src/main/java/cc/polyfrost/oneconfig/utils/commands/annotations/Name.java index ef178a0..f802697 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/commands/annotations/Name.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/commands/annotations/Name.java @@ -16,6 +16,7 @@ import java.lang.annotation.Target; public @interface Name { /** * The name of the parameter. + * * @return The name of the parameter. */ String value(); diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/commands/annotations/SubCommand.java b/src/main/java/cc/polyfrost/oneconfig/utils/commands/annotations/SubCommand.java index b1cf035..1bfbd53 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/commands/annotations/SubCommand.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/commands/annotations/SubCommand.java @@ -16,18 +16,21 @@ import java.lang.annotation.Target; public @interface SubCommand { /** * The name of the command. + * * @return The name of the command. */ String value(); /** * The aliases of the command. + * * @return The aliases of the command. */ String[] aliases() default {}; /** * The description of the command. + * * @return The description of the command. */ String description() default ""; diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/ArgumentParser.java b/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/ArgumentParser.java index d9d51b0..8bf811b 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/ArgumentParser.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/ArgumentParser.java @@ -3,10 +3,36 @@ package cc.polyfrost.oneconfig.utils.commands.arguments; import com.google.common.reflect.TypeToken; import org.jetbrains.annotations.Nullable; -@SuppressWarnings("unstable") +import java.lang.reflect.Parameter; +import java.util.Collections; +import java.util.List; + +@SuppressWarnings("UnstableApiUsage") public abstract class ArgumentParser<T> { - private final TypeToken<T> type = new TypeToken<T>(getClass()) {}; + private final TypeToken<T> type = new TypeToken<T>(getClass()) { + }; public final Class<?> typeClass = type.getRawType(); + + /** + * Parses the given string into an object of the type specified by this parser. + * Should return null if the string cannot be parsed. + * + * @param arguments The string to parse. + * @return The parsed object, or null if the string cannot be parsed. + */ @Nullable public abstract T parse(Arguments arguments); + + /** + * Returns possible completions for the given arguments. + * Should return an empty list or null if no completions are possible. + * + * @param arguments The arguments to complete. + * @param parameter The parameter to complete. + * @return A list of possible completions, or an empty list or null if no completions are possible. + */ + @Nullable + public List<String> complete(Arguments arguments, Parameter parameter) { + return Collections.emptyList(); + } } diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/Arguments.java b/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/Arguments.java index 74a0840..f35cf46 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/Arguments.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/Arguments.java @@ -1,9 +1,9 @@ package cc.polyfrost.oneconfig.utils.commands.arguments; public class Arguments { - private int position = 0; public final String[] args; public final boolean greedy; + private int position = 0; public Arguments(String[] args, boolean greedy) { this.args = args; diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/BooleanParser.java b/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/BooleanParser.java index dfdca2d..7411cbe 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/BooleanParser.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/BooleanParser.java @@ -1,11 +1,31 @@ package cc.polyfrost.oneconfig.utils.commands.arguments; +import com.google.common.collect.Lists; import org.jetbrains.annotations.Nullable; +import java.lang.reflect.Parameter; +import java.util.List; +import java.util.Locale; + public class BooleanParser extends ArgumentParser<Boolean> { + private static final List<String> VALUES = Lists.newArrayList("true", "false"); + @Override public @Nullable Boolean parse(Arguments arguments) { return Boolean.parseBoolean(arguments.poll()); } + + @Override + public @Nullable List<String> complete(Arguments arguments, Parameter parameter) { + String value = arguments.poll(); + if (value != null && !value.trim().isEmpty()) { + for (String v : VALUES) { + if (v.startsWith(value.toLowerCase(Locale.ENGLISH))) { + return Lists.newArrayList(v); + } + } + } + return VALUES; + } } diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/DoubleParser.java b/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/DoubleParser.java index 8c85849..4379e3a 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/DoubleParser.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/DoubleParser.java @@ -5,6 +5,10 @@ import org.jetbrains.annotations.Nullable; public class DoubleParser extends ArgumentParser<Double> { @Override public @Nullable Double parse(Arguments arguments) { - return Double.parseDouble(arguments.poll()); + try { + return Double.parseDouble(arguments.poll()); + } catch (NumberFormatException e) { + return null; + } } } diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/FloatParser.java b/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/FloatParser.java index 7053fcb..08e0a45 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/FloatParser.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/FloatParser.java @@ -6,6 +6,10 @@ public class FloatParser extends ArgumentParser<Float> { @Override public @Nullable Float parse(Arguments arguments) { - return Float.parseFloat(arguments.poll()); + try { + return Float.parseFloat(arguments.poll()); + } catch (NumberFormatException e) { + return null; + } } } diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/IntegerParser.java b/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/IntegerParser.java index 6910d4b..89f4eca 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/IntegerParser.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/IntegerParser.java @@ -3,6 +3,10 @@ package cc.polyfrost.oneconfig.utils.commands.arguments; public class IntegerParser extends ArgumentParser<Integer> { @Override public Integer parse(Arguments arguments) { - return Integer.parseInt(arguments.poll()); + try { + return Integer.parseInt(arguments.poll()); + } catch (NumberFormatException e) { + return null; + } } } diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/hypixel/HypixelUtils.java b/src/main/java/cc/polyfrost/oneconfig/utils/hypixel/HypixelUtils.java index d7a9b0d..a952053 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/hypixel/HypixelUtils.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/hypixel/HypixelUtils.java @@ -2,17 +2,17 @@ package cc.polyfrost.oneconfig.utils.hypixel; import cc.polyfrost.oneconfig.events.EventManager; import cc.polyfrost.oneconfig.events.event.*; -import cc.polyfrost.oneconfig.libs.eventbus.Subscribe; -import cc.polyfrost.oneconfig.libs.universal.UChat; -import cc.polyfrost.oneconfig.libs.universal.UMinecraft; -import cc.polyfrost.oneconfig.libs.universal.wrappers.UPlayer; -import cc.polyfrost.oneconfig.libs.universal.wrappers.message.UTextComponent; import cc.polyfrost.oneconfig.utils.JsonUtils; import cc.polyfrost.oneconfig.utils.Multithreading; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import gg.essential.universal.UChat; +import gg.essential.universal.UMinecraft; +import gg.essential.universal.wrappers.UPlayer; +import gg.essential.universal.wrappers.message.UTextComponent; +import me.kbrewster.eventbus.Subscribe; import java.util.Locale; import java.util.concurrent.TimeUnit; @@ -133,6 +133,7 @@ public class HypixelUtils { /** * Returns whether the player is in game. + * * @return Whether the player is in game. */ public boolean isInGame() { @@ -141,6 +142,7 @@ public class HypixelUtils { /** * Returns the current {@link LocrawInfo}. + * * @return The current {@link LocrawInfo}. * @see LocrawInfo */ @@ -150,6 +152,7 @@ public class HypixelUtils { /** * Returns the previous {@link LocrawInfo}. + * * @return The previous {@link LocrawInfo}. * @see LocrawInfo */ |