diff --git a/Chroma-Core/pom.xml b/Chroma-Core/pom.xml index e457d89..b2a7863 100755 --- a/Chroma-Core/pom.xml +++ b/Chroma-Core/pom.xml @@ -72,7 +72,6 @@ me.lucko:commodore - org.javatuples:javatuples @@ -226,11 +225,6 @@ 1.11 compile - - org.javatuples - javatuples - 1.2 - org.jetbrains.kotlin kotlin-stdlib diff --git a/Chroma-Core/src/main/java/buttondevteam/core/MainPlugin.java b/Chroma-Core/src/main/java/buttondevteam/core/MainPlugin.java index 4d2543b..376e148 100755 --- a/Chroma-Core/src/main/java/buttondevteam/core/MainPlugin.java +++ b/Chroma-Core/src/main/java/buttondevteam/core/MainPlugin.java @@ -106,7 +106,7 @@ public class MainPlugin extends ButtonPlugin { registerCommand(new ComponentCommand()); registerCommand(new ChromaCommand()); TBMCCoreAPI.RegisterEventsForExceptions(new PlayerListener(), this); - TBMCCoreAPI.RegisterEventsForExceptions(getCommand2MC(), this); + TBMCCoreAPI.RegisterEventsForExceptions(Companion.getCommand2MC(), this); ChromaGamerBase.addConverter(commandSender -> Optional.ofNullable(commandSender instanceof ConsoleCommandSender || commandSender instanceof BlockCommandSender ? TBMCPlayer.getPlayer(new UUID(0, 0), TBMCPlayer.class) : null)); //Console & cmdblocks ChromaGamerBase.addConverter(sender -> Optional.ofNullable(sender instanceof Player @@ -125,8 +125,8 @@ public class MainPlugin extends ButtonPlugin { TBMCChatAPI.RegisterChatChannel(new ChatRoom("§bBLUE§f", Color.Blue, "blue")); TBMCChatAPI.RegisterChatChannel(new ChatRoom("§5PURPLE§f", Color.DarkPurple, "purple")); Supplier> playerSupplier = () -> Bukkit.getOnlinePlayers().stream().map(HumanEntity::getName)::iterator; - getCommand2MC().addParamConverter(OfflinePlayer.class, Bukkit::getOfflinePlayer, "Player not found!", playerSupplier); - getCommand2MC().addParamConverter(Player.class, Bukkit::getPlayer, "Online player not found!", playerSupplier); + Companion.getCommand2MC().addParamConverter(OfflinePlayer.class, Bukkit::getOfflinePlayer, "Player not found!", playerSupplier); + Companion.getCommand2MC().addParamConverter(Player.class, Bukkit::getPlayer, "Online player not found!", playerSupplier); if (writePluginList.get()) { try { Files.write(new File("plugins", "plugins.txt").toPath(), Arrays.stream(Bukkit.getPluginManager().getPlugins()).map(p -> (CharSequence) p.getDataFolder().getName())::iterator); diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.kt b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.kt index 7124b04..1e439e9 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.kt +++ b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.kt @@ -5,8 +5,6 @@ import buttondevteam.core.ComponentManager import buttondevteam.lib.TBMCCoreAPI import buttondevteam.lib.architecture.Component.Companion.updateConfig import buttondevteam.lib.chat.Command2MC -import buttondevteam.lib.chat.Command2MC.registerCommand -import buttondevteam.lib.chat.Command2MC.unregisterCommands import buttondevteam.lib.chat.ICommand2MC import lombok.AccessLevel import lombok.Getter @@ -22,8 +20,7 @@ import java.util.function.Function @HasConfig(global = true) abstract class ButtonPlugin : JavaPlugin() { - @Getter(AccessLevel.PROTECTED) - private val iConfig = IHaveConfig { saveConfig() } + protected val iConfig = IHaveConfig { saveConfig() } private var yaml: CommentedConfiguration? = null @Getter(AccessLevel.PROTECTED) @@ -74,7 +71,7 @@ abstract class ButtonPlugin : JavaPlugin() { ComponentManager.unregComponents(this) pluginDisable() if (ConfigData.saveNow(config)) logger.info("Saved configuration changes.") - ButtonPlugin.getCommand2MC().unregisterCommands(this) + command2MC.unregisterCommands(this) } catch (e: Exception) { TBMCCoreAPI.SendException("Error while disabling plugin $name!", e, this) } @@ -122,7 +119,7 @@ abstract class ButtonPlugin : JavaPlugin() { override fun getConfig(): FileConfiguration { if (yaml == null) justReload() - return if (yaml == null) YamlConfiguration() else yaml //Return a temporary instance + return yaml ?: YamlConfiguration() //Return a temporary instance } override fun saveConfig() { @@ -140,16 +137,15 @@ abstract class ButtonPlugin : JavaPlugin() { */ fun registerCommand(command: ICommand2MC) { command.registerToPlugin(this) - ButtonPlugin.getCommand2MC().registerCommand(command) + command2MC.registerCommand(command) } @Retention(AnnotationRetention.RUNTIME) @Target(AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS) annotation class ConfigOpts(val disableConfigGen: Boolean = false) companion object { - @Getter //Needs to be static as we don't know the plugin when a command is handled - - private val command2MC = Command2MC() + //Needs to be static as we don't know the plugin when a command is handled + val command2MC = Command2MC() fun configGenAllowed(obj: Any): Boolean { return !Optional.ofNullable(obj.javaClass.getAnnotation(ConfigOpts::class.java)) .map(Function { obj: ConfigOpts -> obj.disableConfigGen() }).orElse(false) diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.kt b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.kt index bccd5ae..6bcbdef 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.kt +++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.kt @@ -2,9 +2,8 @@ package buttondevteam.lib.chat import buttondevteam.core.MainPlugin import buttondevteam.lib.TBMCCoreAPI -import buttondevteam.lib.chat.Command2.Subcommand import buttondevteam.lib.chat.commands.* -import buttondevteam.lib.player.ChromaGamerBase +import buttondevteam.lib.chat.commands.CommandUtils.core import com.mojang.brigadier.CommandDispatcher import com.mojang.brigadier.arguments.* import com.mojang.brigadier.builder.ArgumentBuilder @@ -15,8 +14,6 @@ import com.mojang.brigadier.tree.CommandNode import com.mojang.brigadier.tree.LiteralCommandNode import lombok.RequiredArgsConstructor import org.bukkit.Bukkit -import org.javatuples.Pair -import org.javatuples.Triplet import java.lang.reflect.Method import java.util.function.Function import java.util.function.Predicate @@ -90,7 +87,7 @@ abstract class Command2, TP : Command2Sender> { */ open fun addParamConverter(cl: Class, converter: Function, errormsg: String, allSupplier: Supplier>) { - paramConverters[cl] = ParamConverter(converter, errormsg, allSupplier) + paramConverters[cl] = ParamConverter(converter, errormsg, allSupplier) } open fun handleCommand(sender: TP, commandline: String): Boolean { @@ -112,22 +109,10 @@ abstract class Command2, TP : Command2Sender> { } //TODO: Add to the help - private fun processSenderType(sender: TP, sd: SubcommandData, params: ArrayList): Boolean { - val sendertype = sd.senderType - val cg: ChromaGamerBase - if (sendertype.isAssignableFrom(sender.javaClass)) params.add(sender) //The command either expects a CommandSender or it is a Player, or some other expected type - else if (sender is Command2MCSender // TODO: This is Minecraft only - && sendertype.isAssignableFrom((sender as Command2MCSender).sender.javaClass)) - params.add((sender as Command2MCSender).sender) - else if ((ChromaGamerBase::class.java.isAssignableFrom(sendertype) && sender is Command2MCSender) - && ChromaGamerBase.getFromSender((sender as Command2MCSender).sender).also { cg = it } != null && cg.javaClass == sendertype) //The command expects a user of our system - params.add(cg) else { - val type = sendertype.simpleName.fold("") { s, ch -> s + if (ch.isUpperCase()) " " + ch.lowercase() else ch } - sender.sendMessage("§cYou need to be a $type to use this command.") - sender.sendMessage(sd.getHelpText(sender)) //Send what the command is about, could be useful for commands like /member where some subcommands aren't player-only - return true - } - return false + open fun convertSenderType(sender: TP, senderType: Class<*>): Any? { + //The command either expects a CommandSender or it is a Player, or some other expected type + if (senderType.isAssignableFrom(sender.javaClass)) return sender + return null } /** @@ -146,17 +131,18 @@ abstract class Command2, TP : Command2Sender> { */ protected fun registerCommandSuper(command: TC): LiteralCommandNode { var mainCommandNode: LiteralCommandNode? = null - for (meth in command.javaClass.getMethods()) { - val ann = meth.getAnnotation(Subcommand::class.java) ?: continue + for (meth in command.javaClass.methods) { + val ann = meth.getAnnotation(Subcommand::class.java) ?: continue val methodPath = CommandUtils.getCommandPath(meth.name, ' ') - val result = registerNodeFromPath(command!!.commandPath + methodPath) - result.value0.addChild(getExecutableNode(meth, command, ann, result.value2, CommandArgumentHelpManager(command))) - if (mainCommandNode == null) mainCommandNode = result.value1 else if (result.value1!!.name != mainCommandNode.name) { + val (lastNode, mainNode, remainingPath) = registerNodeFromPath(command.commandPath + methodPath) + lastNode.addChild(getExecutableNode(meth, command, ann, remainingPath, CommandArgumentHelpManager(command))) + if (mainCommandNode == null) mainCommandNode = mainNode + else if (mainNode!!.name != mainCommandNode.name) { MainPlugin.Instance.logger.warning("Multiple commands are defined in the same class! This is not supported. Class: " + command.javaClass.simpleName) } } if (mainCommandNode == null) { - throw RuntimeException("There are no subcommands defined in the command class " + command.javaClass.getSimpleName() + "!") + throw RuntimeException("There are no subcommands defined in the command class " + command.javaClass.simpleName + "!") } return mainCommandNode } @@ -170,18 +156,18 @@ abstract class Command2, TP : Command2Sender> { * @return The executable node */ private fun getExecutableNode(method: Method, command: TC, ann: Subcommand, path: String, argHelpManager: CommandArgumentHelpManager): LiteralCommandNode { - val paramsAndSenderType = getCommandParametersAndSender(method, argHelpManager) // Param order is important - val params = paramsAndSenderType.value0 + val (params, _) = getCommandParametersAndSender(method, argHelpManager) // Param order is important val paramMap = HashMap() for (param in params) { - paramMap[param!!.name] = param + paramMap[param.name] = param } - val node = CoreCommandBuilder.literal(path, params[0]!!.type, paramMap, params, command) - .helps(command!!.getHelpText(method, ann)).permits { sender: TP -> hasPermission(sender, command, method) } + val node = CoreCommandBuilder.literal(path, params[0].type, paramMap, params, command) + .helps(command.getHelpText(method, ann)).permits { sender: TP -> hasPermission(sender, command, method) } .executes { context: CommandContext -> executeCommand(context) } var parent: ArgumentBuilder = node for (param in params) { // Register parameters in the right order - parent.then(CoreArgumentBuilder.argument(param!!.name, getArgumentType(param), param.optional).also { parent = it }) + val argType = getArgumentType(param) + parent.then(CoreArgumentBuilder.argument(param.name, argType, param.optional).also { parent = it }) } return node.build() } @@ -193,7 +179,7 @@ abstract class Command2, TP : Command2Sender> { * @return The last no-op node that can be used to register the executable node, * the main command node and the last part of the command path (that isn't registered yet) */ - private fun registerNodeFromPath(path: String): Triplet, LiteralCommandNode?, String> { + private fun registerNodeFromPath(path: String): Triple, LiteralCommandNode?, String> { val split = path.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() var parent: CommandNode = dispatcher.root var mainCommand: LiteralCommandNode? = null @@ -203,7 +189,7 @@ abstract class Command2, TP : Command2Sender> { if (child == null) parent.addChild(CoreCommandBuilder.literalNoOp(part).executes { context: CommandContext -> executeHelpText(context) }.build().also { parent = it }) else parent = child if (i == 0) mainCommand = parent as LiteralCommandNode // Has to be a literal, if not, well, error } - return Triplet(parent, mainCommand, split[split.size - 1]) + return Triple(parent, mainCommand, split[split.size - 1]) } /** @@ -214,21 +200,20 @@ abstract class Command2, TP : Command2Sender> { * @return Parameter data objects and the sender type * @throws RuntimeException If there is no sender parameter declared in the method */ - private fun getCommandParametersAndSender(method: Method, argHelpManager: CommandArgumentHelpManager): Pair, Class<*>> { + private fun getCommandParametersAndSender(method: Method, argHelpManager: CommandArgumentHelpManager): Pair, Class<*>> { val parameters = method.parameters - if (parameters.size == 0) throw RuntimeException("No sender parameter for method '$method'") - val ret = arrayOfNulls(parameters.size) + if (parameters.isEmpty()) throw RuntimeException("No sender parameter for method '$method'") val usage = argHelpManager.getParameterHelpForMethod(method) - val paramNames = usage?.split(" ".toRegex())?.dropLastWhile { it.isEmpty() }?.toTypedArray() - for (i in 1 until parameters.size) { - val numAnn = parameters[i].getAnnotation(NumberArg::class.java) - ret[i - 1] = CommandArgument(paramNames?.get(i) ?: "param$i", parameters[i].type, - parameters[i].isVarArgs || parameters[i].isAnnotationPresent(TextArg::class.java), - if (numAnn == null) null else Pair(numAnn.lowerLimit(), numAnn.upperLimit()), - parameters[i].isAnnotationPresent(OptionalArg::class.java), - paramNames?.get(i) ?: "param$i") // TODO: Description (JavaDoc?) - } - return Pair(ret, parameters[0].type) + val paramNames = usage?.split(" ") + return Pair(parameters.zip(paramNames ?: (1 until parameters.size).map { i -> "param$i" }) + .map { (param, name) -> + val numAnn = param.getAnnotation(NumberArg::class.java) + CommandArgument(name, param.type, + param.isVarArgs || param.isAnnotationPresent(TextArg::class.java), + if (numAnn == null) Pair(Double.MIN_VALUE, Double.MAX_VALUE) else Pair(numAnn.lowerLimit, numAnn.upperLimit), + param.isAnnotationPresent(OptionalArg::class.java), + name) + }, parameters[0].type) } /** @@ -238,13 +223,24 @@ abstract class Command2, TP : Command2Sender> { * @param arg Our representation of the command argument * @return The Brigadier representation of the command argument */ - private fun getArgumentType(arg: CommandArgument?): ArgumentType<*> { + private fun getArgumentType(arg: CommandArgument?): ArgumentType { val ptype = arg!!.type - val lowerLimit: Number = arg.limits.value0 - val upperLimit: Number = arg.limits.value1 - return if (arg.greedy) StringArgumentType.greedyString() else if (ptype == String::class.java) StringArgumentType.word() else if (ptype == Int::class.javaPrimitiveType || ptype == Int::class.java || ptype == Byte::class.javaPrimitiveType || ptype == Byte::class.java || ptype == Short::class.javaPrimitiveType || ptype == Short::class.java) IntegerArgumentType.integer(lowerLimit.toInt(), upperLimit.toInt()) else if (ptype == Long::class.javaPrimitiveType || ptype == Long::class.java) LongArgumentType.longArg(lowerLimit.toLong(), upperLimit.toLong()) else if (ptype == Float::class.javaPrimitiveType || ptype == Float::class.java) FloatArgumentType.floatArg(lowerLimit.toFloat(), upperLimit.toFloat()) else if (ptype == Double::class.javaPrimitiveType || ptype == Double::class.java) DoubleArgumentType.doubleArg(lowerLimit.toDouble(), upperLimit.toDouble()) else if (ptype == Char::class.javaPrimitiveType || ptype == Char::class.java) StringArgumentType.word() else if (ptype == Boolean::class.javaPrimitiveType || ptype == Boolean::class.java) BoolArgumentType.bool() else { - StringArgumentType.word() - } + val (lowerLimit, upperLimit) = arg.limits + return if (arg.greedy) StringArgumentType.greedyString() + else if (ptype == String::class.java) StringArgumentType.word() + else if (ptype == Int::class.javaPrimitiveType || ptype == Int::class.java + || ptype == Byte::class.javaPrimitiveType || ptype == Byte::class.java + || ptype == Short::class.javaPrimitiveType || ptype == Short::class.java) + IntegerArgumentType.integer(lowerLimit.toInt(), upperLimit.toInt()) + else if (ptype == Long::class.javaPrimitiveType || ptype == Long::class.java) + LongArgumentType.longArg(lowerLimit.toLong(), upperLimit.toLong()) + else if (ptype == Float::class.javaPrimitiveType || ptype == Float::class.java) + FloatArgumentType.floatArg(lowerLimit.toFloat(), upperLimit.toFloat()) + else if (ptype == Double::class.javaPrimitiveType || ptype == Double::class.java) + DoubleArgumentType.doubleArg(lowerLimit, upperLimit) + else if (ptype == Char::class.javaPrimitiveType || ptype == Char::class.java) StringArgumentType.word() + else if (ptype == Boolean::class.javaPrimitiveType || ptype == Boolean::class.java) BoolArgumentType.bool() + else StringArgumentType.word() } /** @@ -277,6 +273,11 @@ abstract class Command2, TP : Command2Sender> { return; } // TODO: WIP + + val type = sendertype.simpleName.fold("") { s, ch -> s + if (ch.isUpperCase()) " " + ch.lowercase() else ch } + sender.sendMessage("§cYou need to be a $type to use this command.") + sender.sendMessage(sd.getHelpText(sender)) //Send what the command is about, could be useful for commands like /member where some subcommands aren't player-only + if (processSenderType(sender, sd, params, parameterTypes)) return; // Checks if the sender is the wrong type val args = parsed.getContext().getArguments(); for (var arg : sd.arguments.entrySet()) {*/ @@ -325,16 +326,15 @@ abstract class Command2, TP : Command2Sender> { } abstract fun hasPermission(sender: TP, command: TC, subcommand: Method?): Boolean - val commandsText: Array - get() = commandHelp.toTypedArray() + val commandsText: Array get() = commandHelp.toTypedArray() /** * Get all registered command nodes. This returns all registered Chroma commands with all the information about them. * * @return A set of command node objects containing the commands */ - val commandNodes: Set?> - get() = dispatcher.root.children.stream().map { node: CommandNode? -> node as CoreCommandNode? }.collect(Collectors.toUnmodifiableSet()) + val commandNodes: Set> + get() = dispatcher.root.children.stream().map { node: CommandNode -> node.core() }.collect(Collectors.toUnmodifiableSet()) /** * Get a node that belongs to the given command. @@ -343,7 +343,7 @@ abstract class Command2, TP : Command2Sender> { * @return A command node */ fun getCommandNode(command: String?): CoreCommandNode { - return dispatcher.root.getChild(command) as CoreCommandNode + return dispatcher.root.getChild(command).core() } /** @@ -352,7 +352,7 @@ abstract class Command2, TP : Command2Sender> { * @param command The command class (object) to unregister */ fun unregisterCommand(command: ICommand2) { - dispatcher.root.children.removeIf { node: CommandNode -> (node as CoreCommandNode).data.command === command } + dispatcher.root.children.removeIf { node: CommandNode -> node.core().data.command === command } } /** @@ -360,14 +360,14 @@ abstract class Command2, TP : Command2Sender> { * * @param condition The condition for removing a given command */ - fun unregisterCommandIf(condition: Predicate?>, nested: Boolean) { - dispatcher.root.children.removeIf { node: CommandNode? -> condition.test(node as CoreCommandNode?) } - if (nested) for (child in dispatcher.root.children) unregisterCommandIf(condition, child as CoreCommandNode) + fun unregisterCommandIf(condition: Predicate>, nested: Boolean) { + dispatcher.root.children.removeIf { node: CommandNode -> condition.test(node.core()) } + if (nested) for (child in dispatcher.root.children) unregisterCommandIf(condition, child.core()) } - private fun unregisterCommandIf(condition: Predicate?>, root: CoreCommandNode) { + private fun unregisterCommandIf(condition: Predicate>, root: CoreCommandNode) { // Can't use getCoreChildren() here because the collection needs to be modifiable - root.children.removeIf { node: CommandNode? -> condition.test(node as CoreCommandNode?) } + root.children.removeIf { node: CommandNode -> condition.test(node.core()) } for (child in root.coreChildren) unregisterCommandIf(condition, child) } } \ No newline at end of file diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.kt b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.kt index 278894b..b65fa4a 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.kt +++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.kt @@ -28,7 +28,6 @@ import org.bukkit.entity.Player import org.bukkit.event.Listener import org.bukkit.permissions.Permission import org.bukkit.permissions.PermissionDefault -import org.javatuples.Triplet import java.lang.reflect.Method import java.lang.reflect.Parameter import java.util.* @@ -36,7 +35,7 @@ import java.util.function.BiConsumer import java.util.function.Function import java.util.function.Supplier -class Command2MC : Command2('/', true), Listener { +class Command2MC : Command2('/', true), Listener { /** * Don't use directly, use the method in Component and ButtonPlugin to automatically unregister the command when needed. * @@ -149,8 +148,25 @@ class Command2MC : Command2('/', true), Listene super.addParamConverter(cl, converter, "§c$errormsg", allSupplier) } + override fun convertSenderType(sender: Command2MCSender, senderType: Class<*>): Any? { + val original = super.convertSenderType(sender, senderType) + if (original != null) { + return original + } + // Check Bukkit sender type + if (senderType.isAssignableFrom(sender.sender.javaClass)) + return sender.sender + //The command expects a user of our system + if (ChromaGamerBase::class.java.isAssignableFrom(senderType)) { + val cg = ChromaGamerBase.getFromSender(sender.sender) + if (cg?.javaClass == senderType) + return cg + } + return null + } + fun unregisterCommands(plugin: ButtonPlugin) { - unregisterCommandIf({ node: CoreCommandNode -> Optional.ofNullable(node.data.command).map { obj: ICommand2MC -> obj.plugin }.map { obj: ButtonPlugin? -> plugin.equals(obj) }.orElse(false) }, true) + unregisterCommandIf({ node -> Optional.ofNullable(node.data.command).map { obj -> obj.plugin }.map { obj -> plugin == obj }.orElse(false) }, true) } fun unregisterCommands(component: Component<*>) { diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/chat/commands/CommandArgument.java b/Chroma-Core/src/main/java/buttondevteam/lib/chat/commands/CommandArgument.java deleted file mode 100644 index 8620c10..0000000 --- a/Chroma-Core/src/main/java/buttondevteam/lib/chat/commands/CommandArgument.java +++ /dev/null @@ -1,17 +0,0 @@ -package buttondevteam.lib.chat.commands; - -import lombok.RequiredArgsConstructor; -import org.javatuples.Pair; - -/** - * A command argument's information to be used to construct the command. - */ -@RequiredArgsConstructor -public class CommandArgument { - public final String name; - public final Class type; - public final boolean greedy; - public final Pair limits; - public final boolean optional; - public final String description; -} diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/chat/commands/CommandArgument.kt b/Chroma-Core/src/main/java/buttondevteam/lib/chat/commands/CommandArgument.kt new file mode 100644 index 0000000..90b6c78 --- /dev/null +++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/commands/CommandArgument.kt @@ -0,0 +1,13 @@ +package buttondevteam.lib.chat.commands + +/** + * A command argument's information to be used to construct the command. + */ +class CommandArgument( + val name: String, + val type: Class<*>, + val greedy: Boolean, + val limits: Pair, + val optional: Boolean, + val description: String +) diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/chat/commands/CommandUtils.java b/Chroma-Core/src/main/java/buttondevteam/lib/chat/commands/CommandUtils.java deleted file mode 100644 index fd3db08..0000000 --- a/Chroma-Core/src/main/java/buttondevteam/lib/chat/commands/CommandUtils.java +++ /dev/null @@ -1,19 +0,0 @@ -package buttondevteam.lib.chat.commands; - -import lombok.experimental.UtilityClass; -import org.jetbrains.annotations.NotNull; - -@UtilityClass -public class CommandUtils { - /** - * Returns the path of the given subcommand excluding the class' path. It will start with the given replace char. - * - * @param methodName The method's name, method.getName() - * @param replaceChar The character to use between subcommands - * @return The command path starting with the replacement char. - */ - @NotNull - public static String getCommandPath(String methodName, char replaceChar) { - return methodName.equals("def") ? "" : replaceChar + methodName.replace('_', replaceChar).toLowerCase(); - } -} diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/chat/commands/CommandUtils.kt b/Chroma-Core/src/main/java/buttondevteam/lib/chat/commands/CommandUtils.kt new file mode 100644 index 0000000..518c25a --- /dev/null +++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/commands/CommandUtils.kt @@ -0,0 +1,25 @@ +package buttondevteam.lib.chat.commands + +import buttondevteam.lib.chat.Command2Sender +import buttondevteam.lib.chat.CoreCommandNode +import buttondevteam.lib.chat.ICommand2 +import com.mojang.brigadier.tree.CommandNode +import java.util.* + +object CommandUtils { + /** + * Returns the path of the given subcommand excluding the class' path. It will start with the given replace char. + * + * @param methodName The method's name, method.getName() + * @param replaceChar The character to use between subcommands + * @return The command path starting with the replacement char. + */ + fun getCommandPath(methodName: String, replaceChar: Char): String { + return if (methodName == "def") "" else replaceChar.toString() + methodName.replace('_', replaceChar).lowercase(Locale.getDefault()) + } + + @Suppress("UNCHECKED_CAST") + fun > CommandNode.core(): CoreCommandNode { + return this as CoreCommandNode + } +} \ No newline at end of file diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/player/ChromaGamerBase.java b/Chroma-Core/src/main/java/buttondevteam/lib/player/ChromaGamerBase.java index a03aa4f..2890407 100755 --- a/Chroma-Core/src/main/java/buttondevteam/lib/player/ChromaGamerBase.java +++ b/Chroma-Core/src/main/java/buttondevteam/lib/player/ChromaGamerBase.java @@ -153,7 +153,7 @@ public abstract class ChromaGamerBase { * @param sender The sender to use * @return A user as returned by a converter or null if none can supply it */ - public static ChromaGamerBase getFromSender(CommandSender sender) { + public static ChromaGamerBase getFromSender(CommandSender sender) { // TODO: Use Command2Sender for (val converter : senderConverters) { val ocg = converter.apply(sender); if (ocg.isPresent())