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 f8a213f..3d983e5 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.kt +++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.kt @@ -219,7 +219,7 @@ abstract class Command2, TP : Command2Sender>( if (params.isEmpty() || getArgNodes(node, params.toMutableList())) { node.executes(::executeCommand) } - return node.build().coreExecutable() ?: throw IllegalStateException("Command node should be executable but isn't: $fullPath") + return node.build().coreExecutable() ?: error("Command node should be executable but isn't: $fullPath") } /** @@ -296,19 +296,21 @@ abstract class Command2, TP : Command2Sender>( 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 + else if (ptype == Int::class.javaPrimitiveType || ptype == Int::class.javaObjectType + || ptype == Byte::class.javaPrimitiveType || ptype == Byte::class.javaObjectType + || ptype == Short::class.javaPrimitiveType || ptype == Short::class.javaObjectType ) IntegerArgumentType.integer(lowerLimit.toInt(), upperLimit.toInt()) - else if (ptype == Long::class.javaPrimitiveType || ptype == Long::class.java) + else if (ptype == Long::class.javaPrimitiveType || ptype == Long::class.javaObjectType) LongArgumentType.longArg(lowerLimit.toLong(), upperLimit.toLong()) - else if (ptype == Float::class.javaPrimitiveType || ptype == Float::class.java) + else if (ptype == Float::class.javaPrimitiveType || ptype == Float::class.javaObjectType) FloatArgumentType.floatArg(lowerLimit.toFloat(), upperLimit.toFloat()) - else if (ptype == Double::class.javaPrimitiveType || ptype == Double::class.java) + else if (ptype == Double::class.javaPrimitiveType || ptype == Double::class.javaObjectType) 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 if (ptype == Char::class.javaPrimitiveType || ptype == Char::class.javaObjectType) + StringArgumentType.word() + else if (ptype == Boolean::class.javaPrimitiveType || ptype == Boolean::class.javaObjectType) + BoolArgumentType.bool() else StringArgumentType.word() } @@ -320,10 +322,10 @@ abstract class Command2, TP : Command2Sender>( * @return Vanilla command success level (0) */ private fun executeHelpText(context: CommandContext): Int { - val node = context.nodes.lastOrNull()?.node ?: throw IllegalStateException() - val helpText = node.subcommandDataNoOp()?.getHelpText(context.source) ?: throw IllegalStateException() + val node = context.nodes.lastOrNull()?.node ?: error("No nodes found when executing help text for ${context.input}!") + val helpText = node.subcommandDataNoOp()?.getHelpText(context.source) ?: error("No subcommand data found when executing help text for ${context.input}") if (node.isCommand()) { - val subs = getSubcommands(node.coreCommandNoOp()!!).map { commandChar + it.data.fullPath } + val subs = getSubcommands(node.coreCommandNoOp()!!).map { commandChar + it.data.fullPath }.sorted() context.source.sendMessage(helpText + "${ChatColor.GOLD}---- Subcommands ----" + subs) } return 0 @@ -336,7 +338,7 @@ abstract class Command2, TP : Command2Sender>( * @return Vanilla command success level (0) */ protected open fun executeCommand(context: CommandContext): Int { - val sd = context.nodes.lastOrNull()?.node?.subcommandData<_, TC>() ?: throw IllegalStateException("Could not find suitable command node for command ${context.input}") + val sd = context.nodes.lastOrNull()?.node?.subcommandData<_, TC>() ?: error("Could not find suitable command node for command ${context.input}") val sender = context.source if (!sd.hasPermission(sender)) { @@ -348,7 +350,7 @@ abstract class Command2, TP : Command2Sender>( val convertedSender = convertSenderType(sender, sd.senderType) if (convertedSender == null) { //TODO: Should have a prettier display of Command2 classes here - val type = sd.senderType.simpleName.fold("") { s, ch -> s + if (ch.isUpperCase()) " " + ch.lowercase() else ch } + val type = sd.senderType.simpleName.fold("") { s, ch -> s + if (ch.isUpperCase()) " " + ch.lowercase() else ch }.trim() sender.sendMessage("${ChatColor.RED}You need to be a $type to use this command.") executeHelpText(context) //Send what the command is about, could be useful for commands like /member where some subcommands aren't player-only return 0 @@ -373,10 +375,14 @@ abstract class Command2, TP : Command2Sender>( } else { val userArgument = context.getArgument(argument.name, String::class.java) val converter = paramConverters[argument.type]?.converter - ?: throw IllegalStateException("No suitable converter found for ${argument.type} ${argument.name}") + ?: error("No suitable converter found for ${argument.type} ${argument.name}") params.add(converter.apply(userArgument)) } } catch (e: IllegalArgumentException) { + if (ChromaUtils.isTest && e.message?.contains("No such argument '${argument.name}' exists on this command") != true) { + println("For command ${sd.fullPath}:") + e.printStackTrace() + } if (argument.optional) { params.add(argument.type.getDefaultForEasilyRepresentable()) } else { 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 552438f..bbe94df 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.kt +++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.kt @@ -279,7 +279,7 @@ class Command2MC : Command2('/', true), Listener for (suggestion in suggestions) sbuilder.suggest(suggestion) } } - if (argData.type === Boolean::class.javaPrimitiveType || argData.type === Boolean::class.java) + if (argData.type === Boolean::class.javaPrimitiveType || argData.type === Boolean::class.javaObjectType) sbuilder.suggest("true").suggest("false") val loweredInput = sbuilder.remaining.lowercase(Locale.getDefault()) // The list is automatically ordered, so we need to put the at the end after that diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/chat/ICommand2MC.kt b/Chroma-Core/src/main/java/buttondevteam/lib/chat/ICommand2MC.kt index 61b3494..67107a6 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/chat/ICommand2MC.kt +++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/ICommand2MC.kt @@ -7,16 +7,16 @@ import buttondevteam.lib.architecture.Component abstract class ICommand2MC : ICommand2(command2MC) { private var _plugin: ButtonPlugin? = null var plugin: ButtonPlugin - get() = _plugin ?: throw IllegalStateException("The command is not registered to a Button plugin!") + get() = _plugin ?: error("The command is not registered to a Button plugin!") private set(value) { - if (_plugin != null) throw IllegalStateException("The command is already assigned to a Button plugin!") + if (_plugin != null) error("The command is already assigned to a Button plugin!") _plugin = value } private var _component: Component<*>? = null var component: Component<*>? get() = _component private set(value) { - if (_component != null) throw IllegalStateException("The command is already assigned to a component!") + if (_component != null) error("The command is already assigned to a component!") _component = value } diff --git a/Chroma-Core/src/test/kotlin/buttondevteam/lib/chat/test/Command2MCCommands.kt b/Chroma-Core/src/test/kotlin/buttondevteam/lib/chat/test/Command2MCCommands.kt index 33041a6..1f19512 100644 --- a/Chroma-Core/src/test/kotlin/buttondevteam/lib/chat/test/Command2MCCommands.kt +++ b/Chroma-Core/src/test/kotlin/buttondevteam/lib/chat/test/Command2MCCommands.kt @@ -6,6 +6,7 @@ import buttondevteam.lib.chat.Command2MCSender import buttondevteam.lib.chat.CommandClass import buttondevteam.lib.chat.ICommand2MC import buttondevteam.lib.player.TBMCPlayer +import org.bukkit.OfflinePlayer abstract class Command2MCCommands { @CommandClass(helpText = ["Test command", "Used for testing"]) @@ -97,6 +98,16 @@ abstract class Command2MCCommands { } } + @CommandClass + object TestParamsCommand : ICommand2MC(), ITestCommand2MC { + override var testCommandReceived: String? = null + + @Command2.Subcommand + fun def(sender: OfflinePlayer, testInt: Int?, testLong: Long?, testDouble: Double?, testDouble2: Double) { + testCommandReceived = "$testInt $testLong $testDouble $testDouble2 ${sender.name}" + } + } + interface ITestCommand2MC { var testCommandReceived: String? } diff --git a/Chroma-Core/src/test/kotlin/buttondevteam/lib/chat/test/Command2MCTest.kt b/Chroma-Core/src/test/kotlin/buttondevteam/lib/chat/test/Command2MCTest.kt index a204a6c..303fa24 100644 --- a/Chroma-Core/src/test/kotlin/buttondevteam/lib/chat/test/Command2MCTest.kt +++ b/Chroma-Core/src/test/kotlin/buttondevteam/lib/chat/test/Command2MCTest.kt @@ -5,7 +5,9 @@ import buttondevteam.core.MainPlugin import buttondevteam.core.component.channel.Channel import buttondevteam.lib.architecture.ButtonPlugin import buttondevteam.lib.chat.Command2MCSender +import buttondevteam.lib.chat.ICommand2MC import buttondevteam.lib.chat.commands.CommandUtils.coreExecutable +import buttondevteam.lib.chat.test.Command2MCCommands.* import buttondevteam.lib.player.ChromaGamerBase import buttondevteam.lib.player.TBMCPlayer import org.junit.jupiter.api.MethodOrderer @@ -34,22 +36,24 @@ class Command2MCTest { @Test @Order(2) fun testRegisterCommand() { - MainPlugin.instance.registerCommand(Command2MCCommands.TestCommand) + TestCommand.register() val nodes = ButtonPlugin.command2MC.commandNodes assert(nodes.size == 1) assert(nodes.first().literal == "test") - val coreExecutable = nodes.first().coreExecutable() - assertEquals(Command2MCCommands.TestCommand::class.qualifiedName, coreExecutable?.data?.command?.let { it::class.qualifiedName }, "The command class name doesn't match or command is null") + val coreExecutable = nodes.first().coreExecutable() + assertEquals(TestCommand::class.qualifiedName, coreExecutable?.data?.command?.let { it::class.qualifiedName }, "The command class name doesn't match or command is null") assertEquals("test", coreExecutable?.data?.argumentsInOrder?.firstOrNull()?.name, "Failed to get correct argument name") assertEquals(String::class.java, coreExecutable?.data?.arguments?.get("test")?.type, "The argument could not be found or type doesn't match") assertEquals(Command2MCSender::class.java, coreExecutable?.data?.senderType, "The sender's type doesn't seem to be stored correctly") - MainPlugin.instance.registerCommand(Command2MCCommands.NoArgTestCommand) - assertEquals("No sender parameter for method '${Command2MCCommands.ErroringTestCommand::class.java.getMethod("def")}'", assertFails { MainPlugin.instance.registerCommand(Command2MCCommands.ErroringTestCommand) }.message) - MainPlugin.instance.registerCommand(Command2MCCommands.MultiArgTestCommand) + NoArgTestCommand.register() + val errCmd = ErroringTestCommand + assertEquals("No sender parameter for method '${errCmd::class.java.getMethod("def")}'", assertFails { ErroringTestCommand.register() }.message) + MultiArgTestCommand.register() - MainPlugin.instance.registerCommand(Command2MCCommands.TestNoMainCommand1) - MainPlugin.instance.registerCommand(Command2MCCommands.TestNoMainCommand2) + TestNoMainCommand1.register() + TestNoMainCommand2.register() + TestParamsCommand.register() } @Test @@ -95,20 +99,20 @@ class Command2MCTest { return messageReceived } } - runCommand(sender, "/test hmm", Command2MCCommands.TestCommand, "hmm") - runCommand(sender, "/noargtest", Command2MCCommands.NoArgTestCommand, "TestPlayer") + sender.runCommand("/test hmm", TestCommand, "hmm") + sender.runCommand("/noargtest", NoArgTestCommand, "TestPlayer") assertFails { ButtonPlugin.command2MC.handleCommand(sender, "/noargtest failing") } runFailingCommand(sender, "/erroringtest") - runCommand(sender, "/multiargtest test hmm mhm", Command2MCCommands.MultiArgTestCommand, "hmmmhm") - runCommand(sender, "/multiargtest test2 true 19", Command2MCCommands.MultiArgTestCommand, "true 19") + sender.runCommand("/multiargtest test hmm mhm", MultiArgTestCommand, "hmmmhm") + sender.runCommand("/multiargtest test2 true 19", MultiArgTestCommand, "true 19") - runCommand(sender, "/multiargtest testoptional", Command2MCCommands.MultiArgTestCommand, "false") - runCommand(sender, "/multiargtest testoptional true", Command2MCCommands.MultiArgTestCommand, "true") - runCommand(sender, "/multiargtest testoptionalmulti true teszt", Command2MCCommands.MultiArgTestCommand, "true teszt") - runCommand(sender, "/multiargtest testoptionalmulti true", Command2MCCommands.MultiArgTestCommand, "true null") - runCommand(sender, "/multiargtest testoptionalmulti", Command2MCCommands.MultiArgTestCommand, "false null") + sender.runCommand("/multiargtest testoptional", MultiArgTestCommand, "false") + sender.runCommand("/multiargtest testoptional true", MultiArgTestCommand, "true") + sender.runCommand("/multiargtest testoptionalmulti true teszt", MultiArgTestCommand, "true teszt") + sender.runCommand("/multiargtest testoptionalmulti true", MultiArgTestCommand, "true null") + sender.runCommand("/multiargtest testoptionalmulti", MultiArgTestCommand, "false null") - runCommand(sender, "/test plugin Chroma-Core", Command2MCCommands.TestCommand, "Chroma-Core") + sender.runCommand("/test plugin Chroma-Core", TestCommand, "Chroma-Core") assertFails { ButtonPlugin.command2MC.handleCommand(sender, "/test playerfail TestPlayer") } assertEquals("Test command\n" + @@ -117,16 +121,22 @@ class Command2MCTest { "/test playerfail\n" + "/test plugin", sender.withMessageReceive { ButtonPlugin.command2MC.handleCommand(sender, "/test") }) - runCommand(sender, "/some test cmd", Command2MCCommands.TestNoMainCommand1, "TestPlayer") - runCommand(sender, "/some another cmd", Command2MCCommands.TestNoMainCommand2, "TestPlayer") + sender.runCommand("/some test cmd", TestNoMainCommand1, "TestPlayer") + sender.runCommand("/some another cmd", TestNoMainCommand2, "TestPlayer") assertEquals("ยง6---- Subcommands ----\n" + - "/some test cmd\n" + - "/some another cmd", sender.withMessageReceive { ButtonPlugin.command2MC.handleCommand(sender, "/some") }) + "/some another cmd\n" + + "/some test cmd", sender.withMessageReceive { ButtonPlugin.command2MC.handleCommand(sender, "/some") }) + + sender.runCommand("/testparams 12 34 56 78", TestParamsCommand, "12 34 56.0 78.0 Player0") } - private fun runCommand(sender: Command2MCSender, command: String, obj: Command2MCCommands.ITestCommand2MC, expected: String) { - assert(ButtonPlugin.command2MC.handleCommand(sender, command)) { "Could not find command $command" } + private fun ICommand2MC.register() { + MainPlugin.instance.registerCommand(this) + } + + private fun Command2MCSender.runCommand(command: String, obj: ITestCommand2MC, expected: String) { + assert(ButtonPlugin.command2MC.handleCommand(this, command)) { "Could not find command $command" } assertEquals(expected, obj.testCommandReceived) } diff --git a/Chroma-Core/src/test/resources/commands.yml b/Chroma-Core/src/test/resources/commands.yml index 1b77d96..36d9972 100644 --- a/Chroma-Core/src/test/resources/commands.yml +++ b/Chroma-Core/src/test/resources/commands.yml @@ -2,7 +2,7 @@ buttondevteam: lib: chat: test: - Command2MCTest: + Command2MCCommands: TestCommand: def: method: def() @@ -33,6 +33,10 @@ buttondevteam: def: method: def() params: '' + TestParamsCommand: + def: + method: def() + params: 'testInt testLong testDouble testDouble2' core: ComponentCommand: def: