Final Update?

Possibly ready for release?
This commit is contained in:
Paldiu 2022-02-08 23:22:57 -06:00
parent 355d04d9ba
commit 92990227b9
10 changed files with 266 additions and 50 deletions

View File

@ -1,7 +1,7 @@
package io.github.simplex.cl; package io.github.simplex.cl;
import io.github.simplex.api.ICommand; import io.github.simplex.cl.api.ICommand;
import io.github.simplex.api.SubCommand; import io.github.simplex.cl.api.SubCommand;
import io.github.simplex.msgutils.AdvancedColors; import io.github.simplex.msgutils.AdvancedColors;
import io.github.simplex.msgutils.BasicColors; import io.github.simplex.msgutils.BasicColors;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
@ -19,19 +19,35 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
public abstract class CommandBase extends Permissible implements ICommand { public abstract class CommandBase extends Permissible implements ICommand {
public CommandBase(String permission, String permissionMessage, boolean allowConsole) { /**
* @param permission The permission the user should have to run the command
* @param permissionMessage The message to send when the user does not have the permission to run the command.
* @param allowConsole Whether to allow the command to be run anywhere, or only in game.
*/
public CommandBase(@NotNull String permission, String permissionMessage, boolean allowConsole) {
super(permission, permissionMessage, allowConsole); super(permission, permissionMessage, allowConsole);
} }
public CommandBase(String permission, String permissionMessage) { /**
* @param permission The permission the user should have to run the command
* @param permissionMessage The message to send when the user does not have the permission to run the command.
*/
public CommandBase(@NotNull String permission, String permissionMessage) {
this(permission, permissionMessage, true); this(permission, permissionMessage, true);
} }
public CommandBase(String permission, boolean allowConsole) { /**
* @param permission The permission the user should have to run the command
* @param allowConsole Whether to allow the command to be run anywhere, or only in game.
*/
public CommandBase(@NotNull String permission, boolean allowConsole) {
this(permission, "You do not have permission to use this command!", allowConsole); this(permission, "You do not have permission to use this command!", allowConsole);
} }
public CommandBase(String permission) { /**
* @param permission The permission the user should have to run the command
*/
public CommandBase(@NotNull String permission) {
this(permission, "You do not have permission to use this command!", true); this(permission, "You do not have permission to use this command!", true);
} }
@ -55,29 +71,100 @@ public abstract class CommandBase extends Permissible implements ICommand {
return new ArrayList<>(); return new ArrayList<>();
} }
public TextComponent msg(String text) { /**
* Returns a text component for Kyori friendly messaging.
*
* @param text The text to convert to a component
* @return A {@link TextComponent} containing the message provided in {@param text}
*/
@NotNull
public TextComponent msg(@NotNull String text) {
return Component.empty().content(text); return Component.empty().content(text);
} }
public TextComponent msg(String text, BasicColors color) { /**
* Returns a text component for Kyori friendly messaging.
*
* @param text The text to convert to a Component
* @param color The color you'd like the text. These colors are basic and the majority of which are provided by Minecraft's native color system.
* @return A {@link TextComponent} containing the message provided in {@param text} with the provided {@param color}
*/
@NotNull
public TextComponent msg(@NotNull String text, @NotNull BasicColors color) {
return Component.empty().content(text).color(color.getColor()); return Component.empty().content(text).color(color.getColor());
} }
public TextComponent msg(String text, AdvancedColors color) { /**
* Returns a text component for Kyori friendly messaging.
*
* @param text The text to convert to a Component
* @param color The color you'd like the text. These colors are much more diverse for viewing pleasure.
* @return A {@link TextComponent} containing the message provided in {@param text} with the provided {@param color}
*/
@NotNull
public TextComponent msg(@NotNull String text, @NotNull AdvancedColors color) {
return Component.empty().content(text).color(color.getColor()); return Component.empty().content(text).color(color.getColor());
} }
public void subCommand(String name, String[] args, SubCommand command) { /**
if (args[0].equalsIgnoreCase(name)) { * Runs a subcommand provided that the user has the required permission.
command.execute(); *
* @param name The name of the subcommand.
* @param sender The user who executed the command. (Provided by Paper)
* @param permission The permission required to run the subcommand.
* @param args The arguments the user input to run the subcommand. (Provided by Paper)
* @param command The SubCommand to run.
* This is a functional interface to provide easy implementation of the command's details.
*/
public void subCommand(@NotNull String name, @NotNull CommandSender sender, @NotNull String permission, String @NotNull [] args, @NotNull SubCommand command) {
if (!sender.hasPermission(permission)) {
sender.sendMessage(msg(getPermissionMessage()));
return;
}
if (args.length == 0) {
return;
}
String[] tieredCmd = name.split(" ");
if (args.length == 1 && tieredCmd.length == 1) {
if (args[0].equalsIgnoreCase(name)) {
command.execute();
return;
}
}
if (args.length == 2 && tieredCmd.length == 2) {
if (args[0].equalsIgnoreCase(tieredCmd[0]) && args[1].equalsIgnoreCase(tieredCmd[1])) {
command.execute();
return;
}
}
if (args.length == 3 && tieredCmd.length == 3) {
if (args[0].equalsIgnoreCase(tieredCmd[0])
&& args[1].equalsIgnoreCase(tieredCmd[1])
&& args[2].equalsIgnoreCase(tieredCmd[2])) {
command.execute();
return;
}
}
if (args.length == 4 && tieredCmd.length == 4) {
if (args[0].equalsIgnoreCase(tieredCmd[0])
&& args[1].equalsIgnoreCase(tieredCmd[1])
&& args[2].equalsIgnoreCase(tieredCmd[2])
&& args[3].equalsIgnoreCase(tieredCmd[3])) {
command.execute();
}
} }
} }
public Player getPlayer(String name) { @Nullable
public Player getPlayer(@NotNull String name) {
return Bukkit.getServer().getPlayer(name); return Bukkit.getServer().getPlayer(name);
} }
public Player getPlayer(UUID uuid) { @Nullable
public Player getPlayer(@NotNull UUID uuid) {
return Bukkit.getServer().getPlayer(uuid); return Bukkit.getServer().getPlayer(uuid);
} }

View File

@ -3,43 +3,75 @@ package io.github.simplex.cl;
import io.github.simplex.cl.api.annotations.Info; import io.github.simplex.cl.api.annotations.Info;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.reflections.Reflections;
import java.lang.reflect.InvocationTargetException; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Set; import java.util.List;
public class CommandLoader { public class CommandLoader {
private final Plugin plugin; private final Plugin plugin;
private final List<DummyCommand> commandList = new ArrayList<>();
private final String FALLBACK_PREFIX;
public CommandLoader(Plugin plugin) { /**
* @param plugin Your plugin instance
* @param fallbackPrefix The fallback prefix to use in case your plugin fails to provide a namespace.
*/
public CommandLoader(Plugin plugin, String fallbackPrefix) {
this.FALLBACK_PREFIX = fallbackPrefix;
this.plugin = plugin; this.plugin = plugin;
} }
public <T extends CommandBase> void registerCommands(Class<T> commandRoot) { /**
Reflections reflections = new Reflections(commandRoot); * This method will register your command internally within the CommandLoader.
if (commandRoot.getDeclaredAnnotation(Info.class) != null) { * Instances of commands will be cached and readied for loading into Paper.
Set<Class<?>> classSet = reflections.getTypesAnnotatedWith(Info.class); * You should always run this before using {@link CommandLoader#load()}, otherwise your commands will not be loaded.
classSet.forEach(cmd -> { *
Info info = cmd.getDeclaredAnnotation(Info.class); * @param command A new instance of your command which should extend CommandBase.
try { */
CommandBase base = (CommandBase) cmd.getConstructor().newInstance(); public void register(CommandBase command) {
DummyCommand dummy = new DummyCommand(plugin, Class<? extends CommandBase> cmd = command.getClass();
base, if (cmd.getDeclaredAnnotation(Info.class) != null) {
info.name(), Info info = cmd.getDeclaredAnnotation(Info.class);
info.description(), DummyCommand dummy = new DummyCommand(plugin,
info.usage(), command,
Arrays.asList(info.aliases().split(","))); info.name(),
Bukkit.getCommandMap().register(info.name(), "SimplexCL", dummy); info.description(),
} catch (NoSuchMethodException info.usage(),
| InvocationTargetException Arrays.asList(info.aliases().split(",")));
| IllegalAccessException commandList.add(dummy);
| InstantiationException e) {
plugin.getLogger().severe(e.getMessage() + "\n\n\n" + e.getCause());
}
});
} else { } else {
throw new RuntimeException("Missing a required annotation! Unable to load the command."); throw new RuntimeException("Missing a required annotation! Unable to load the command.");
} }
} }
/**
* This will run a loop for each command instance you input and register them all within one method.
* This simply runs the array through a stream and uses a lambda reference to {@link CommandLoader#register(CommandBase)} in order to register the commands.
* Each command will be loaded in the order it is provided.
*
* @param commands An indefinite amount of command instances to be registered.
*/
public void register(CommandBase... commands) {
Arrays.stream(commands).forEachOrdered(this::register);
}
/**
* This will load your commands and initialize them within Paper's CommandMap.
*/
public void load() {
commandList.forEach(cmd -> {
Bukkit.getCommandMap().register(cmd.getName(), FALLBACK_PREFIX, cmd);
});
}
/**
* This will effectively register all your commands and then load them into the Paper CommandMap.
*
* @param commands An indefinite amount of command instances to be registered and loaded.
*/
public void registerAndLoad(CommandBase... commands) {
register(commands);
load();
}
} }

View File

@ -1,5 +1,6 @@
package io.github.simplex.cl; package io.github.simplex.cl;
import net.kyori.adventure.text.Component;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginIdentifiableCommand; import org.bukkit.command.PluginIdentifiableCommand;
@ -12,6 +13,14 @@ public final class DummyCommand extends Command implements PluginIdentifiableCom
private final CommandBase base; private final CommandBase base;
private final Plugin plugin; private final Plugin plugin;
/**
* @param plugin Your plugin instance.
* @param base Your command instance.
* @param name The name of your command
* @param description The description of your command
* @param usageMessage The usage for your command
* @param aliases The aliases for your command.
*/
DummyCommand(@NotNull Plugin plugin, @NotNull CommandBase base, @NotNull String name, @NotNull String description, @NotNull String usageMessage, @NotNull List<String> aliases) { DummyCommand(@NotNull Plugin plugin, @NotNull CommandBase base, @NotNull String name, @NotNull String description, @NotNull String usageMessage, @NotNull List<String> aliases) {
super(name, description, usageMessage, aliases); super(name, description, usageMessage, aliases);
this.setName(name); this.setName(name);
@ -19,16 +28,28 @@ public final class DummyCommand extends Command implements PluginIdentifiableCom
this.setUsage(usageMessage); this.setUsage(usageMessage);
this.setAliases(aliases); this.setAliases(aliases);
this.setPermission(base.getPermission()); this.setPermission(base.getPermission());
this.permissionMessage(Component.empty().content(base.getPermissionMessage()));
this.base = base; this.base = base;
this.plugin = plugin; this.plugin = plugin;
} }
/**
* The actual executor method.
*
* @param sender The user who sent the command
* @param commandLabel The name of the command
* @param args Any additional arguments the user may input
* @return Successfully executed the command or not
*/
@Override @Override
public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
base.onCommand(sender, this, commandLabel, args); base.onCommand(sender, this, commandLabel, args);
return true; return true;
} }
/**
* @return Gets your plugin (Generic)
*/
@Override @Override
public @NotNull Plugin getPlugin() { public @NotNull Plugin getPlugin() {
return plugin; return plugin;

View File

@ -7,24 +7,48 @@ public abstract class Permissible {
private final String permissionMessage; private final String permissionMessage;
private final boolean allowConsole; private final boolean allowConsole;
/**
* @param permission The permission the user should have to run the command
* @param permissionMessage The message to send when the user does not have the permission to run the command.
* @param allowConsole Whether to allow the command to be run anywhere, or only in game.
*/
public Permissible(String permission, String permissionMessage, boolean allowConsole) { public Permissible(String permission, String permissionMessage, boolean allowConsole) {
this.permission = permission; this.permission = permission;
this.permissionMessage = permissionMessage; this.permissionMessage = permissionMessage;
this.allowConsole = allowConsole; this.allowConsole = allowConsole;
} }
/**
* Gets the permission for the command it represents.
*
* @return The permission required to run the command.
*/
public String getPermission() { public String getPermission() {
return permission; return permission;
} }
/**
* Gets the message to display when a user doesn't have permission to run the command.
*
* @return The message to send the user when they do not have the required permission.
*/
public String getPermissionMessage() { public String getPermissionMessage() {
return permissionMessage; return permissionMessage;
} }
/**
* Checks if the source of the command has the permission required to run it.
*
* @param sender The command source
* @return Whether the sender has the permission or not.
*/
public boolean hasPermission(CommandSender sender) { public boolean hasPermission(CommandSender sender) {
return sender.hasPermission(getPermission()); return sender.hasPermission(getPermission());
} }
/**
* @return Whether to allow the command to be run from anywhere, or only players.
*/
public boolean allowConsole() { public boolean allowConsole() {
return allowConsole; return allowConsole;
} }

View File

@ -1,9 +1,16 @@
package io.github.simplex.api; package io.github.simplex.cl.api;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter; import org.bukkit.command.TabCompleter;
public interface ICommand extends CommandExecutor, TabCompleter { public interface ICommand extends CommandExecutor, TabCompleter {
/**
* This is the actual onCommand method. This should be used when you want to execute the command itself.
*
* @param sender The user who sent the command. (Provided by Paper)
* @param args The additional arguments to the command, if applicable (Provided by Paper)
* @param allowConsole Whether the command should be allowed anywhere, or only in game.
*/
void execute(CommandSender sender, String[] args, boolean allowConsole); void execute(CommandSender sender, String[] args, boolean allowConsole);
} }

View File

@ -1,6 +1,9 @@
package io.github.simplex.api; package io.github.simplex.cl.api;
@FunctionalInterface @FunctionalInterface
public interface SubCommand { public interface SubCommand {
/**
* This provides a way to use a functional interface to clearly define subcommands and their actions.
*/
void execute(); void execute();
} }

View File

@ -8,8 +8,23 @@ import java.lang.annotation.Target;
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface Info { public @interface Info {
/**
* @return The name of the command.
*/
String name(); String name();
/**
* @return The description of the command.
*/
String description(); String description();
/**
* @return The proper usage of the command.
*/
String usage(); String usage();
/**
* @return The aliases for the command, separated by commas (alias1,alias2,alias3)
*/
String aliases() default ""; String aliases() default "";
} }

View File

@ -2,8 +2,8 @@ package io.github.simplex.cl.impl;
import io.github.simplex.cl.CommandBase; import io.github.simplex.cl.CommandBase;
import io.github.simplex.cl.api.annotations.Info; import io.github.simplex.cl.api.annotations.Info;
import io.github.simplex.msgutils.AdvancedColors;
import io.github.simplex.msgutils.BasicColors; import io.github.simplex.msgutils.BasicColors;
import net.kyori.adventure.text.format.TextColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@Info(name = "example", description = "An example command implementation to see how this works.", usage = "/example [info]", aliases = "ex, impl") @Info(name = "example", description = "An example command implementation to see how this works.", usage = "/example [info]", aliases = "ex, impl")
@ -16,12 +16,13 @@ public final class ExampleCommand extends CommandBase {
@Override @Override
public void execute(CommandSender sender, String[] args, boolean allowConsole) { public void execute(CommandSender sender, String[] args, boolean allowConsole) {
if (args.length == 1) { subCommand("info", sender, getPermission() + ".info", args, () -> {
subCommand("info", sender.sendMessage(msg("SimplexCL was created by SimplexDevelopment!", BasicColors.GOLD));
args, });
() -> sender.sendMessage(msg("SimplexCL was created by Simplex Development Group.", BasicColors.GOLD)));
return; subCommand("info more", sender, getPermission() + ".info.more", args, () -> {
} sender.sendMessage(msg("https://github.com/SimplexDevelopment", AdvancedColors.FUCHSIA));
});
sender.sendMessage(msg("This is an example command.", BasicColors.BLUE)); sender.sendMessage(msg("This is an example command.", BasicColors.BLUE));
} }

View File

@ -18,7 +18,11 @@ public enum BasicColors {
PURPLE(TextColor.color(255, 0, 255)), PURPLE(TextColor.color(255, 0, 255)),
DARK_PURPLE(TextColor.color(127, 0, 127)), DARK_PURPLE(TextColor.color(127, 0, 127)),
PINK(TextColor.color(255, 105, 180)), PINK(TextColor.color(255, 105, 180)),
DARK_PINK(TextColor.color(231, 84, 128)); DARK_PINK(TextColor.color(231, 84, 128)),
WHITE(TextColor.color(255, 255, 255)),
BLACK(TextColor.color(0, 0, 0)),
LIGHT_GRAY(TextColor.color(127, 127, 127)),
DARK_GRAY(TextColor.color(65, 65, 65));
final TextColor color; final TextColor color;

View File

@ -0,0 +1,22 @@
package io.github.simplex.msgutils;
import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.text.format.TextFormat;
public enum TextFormatting {
BOLD(TextDecoration.BOLD),
ITALICS(TextDecoration.ITALIC),
UNDERLINED(TextDecoration.UNDERLINED),
STRIKETHROUGH(TextDecoration.STRIKETHROUGH),
MAGIC(TextDecoration.OBFUSCATED);
final TextDecoration format;
TextFormatting(TextDecoration format) {
this.format = format;
}
public TextFormat getFormat() {
return format;
}
}