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())