Fix and improve help text code, add subcommand list
This commit is contained in:
parent
d42a4a8a70
commit
9dff03c18e
5 changed files with 90 additions and 21 deletions
|
@ -4,8 +4,10 @@ import buttondevteam.core.MainPlugin
|
|||
import buttondevteam.lib.ChromaUtils
|
||||
import buttondevteam.lib.chat.commands.*
|
||||
import buttondevteam.lib.chat.commands.CommandUtils.coreCommand
|
||||
import buttondevteam.lib.chat.commands.CommandUtils.coreCommandNoOp
|
||||
import buttondevteam.lib.chat.commands.CommandUtils.coreExecutable
|
||||
import buttondevteam.lib.chat.commands.CommandUtils.getDefaultForEasilyRepresentable
|
||||
import buttondevteam.lib.chat.commands.CommandUtils.isCommand
|
||||
import buttondevteam.lib.chat.commands.CommandUtils.isEasilyRepresentable
|
||||
import buttondevteam.lib.chat.commands.CommandUtils.subcommandData
|
||||
import buttondevteam.lib.chat.commands.CommandUtils.subcommandDataNoOp
|
||||
|
@ -233,7 +235,7 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender>(
|
|||
var mainCommand: CoreCommandNode<TP, *>? = null
|
||||
split.dropLast(1).forEachIndexed { i, part ->
|
||||
val child = parent.getChild(part)
|
||||
if (child == null) parent.addChild(CoreCommandBuilder.literalNoOp<TP, TC>(part, getSubcommandList())
|
||||
if (child == null) parent.addChild(CoreCommandBuilder.literalNoOp<TP, TC>(part) { emptyArray() }
|
||||
.executes(::executeHelpText).build().also { parent = it })
|
||||
else parent = child
|
||||
if (i == 0) mainCommand =
|
||||
|
@ -318,7 +320,12 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender>(
|
|||
* @return Vanilla command success level (0)
|
||||
*/
|
||||
private fun executeHelpText(context: CommandContext<TP>): Int {
|
||||
context.source.sendMessage(context.nodes.lastOrNull()?.node?.subcommandDataNoOp()?.getHelpText(context.source))
|
||||
val node = context.nodes.lastOrNull()?.node ?: throw IllegalStateException()
|
||||
val helpText = node.subcommandDataNoOp()?.getHelpText(context.source) ?: throw IllegalStateException()
|
||||
if (node.isCommand()) {
|
||||
val subs = getSubcommands(node.coreCommandNoOp()!!).map { commandChar + it.data.fullPath }
|
||||
context.source.sendMessage(helpText + "${ChatColor.GOLD}---- Subcommands ----" + subs)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
|
@ -343,7 +350,7 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender>(
|
|||
//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 }
|
||||
sender.sendMessage("${ChatColor.RED}You 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
|
||||
executeHelpText(context) //Send what the command is about, could be useful for commands like /member where some subcommands aren't player-only
|
||||
return 0
|
||||
}
|
||||
|
||||
|
@ -352,7 +359,7 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender>(
|
|||
// TODO: Varargs support? (colors?)
|
||||
// TODO: Character handling (strlen)
|
||||
|
||||
executeInvokeCommand(sd, sender, convertedSender, params)
|
||||
executeInvokeCommand(sd, sender, convertedSender, params, context)
|
||||
return 0
|
||||
}
|
||||
|
||||
|
@ -383,13 +390,13 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender>(
|
|||
/**
|
||||
* Invokes the command method with the given sender and parameters.
|
||||
*/
|
||||
private fun executeInvokeCommand(sd: SubcommandData<TC, TP>, sender: TP, actualSender: Any, params: List<Any?>) {
|
||||
private fun executeInvokeCommand(sd: SubcommandData<TC, TP>, sender: TP, actualSender: Any, params: List<Any?>, context: CommandContext<TP>) {
|
||||
val invokeCommand = {
|
||||
try {
|
||||
val ret = sd.executeCommand(actualSender, *params.toTypedArray())
|
||||
if (ret is Boolean) {
|
||||
if (!ret) //Show usage
|
||||
sd.sendHelpText(sender)
|
||||
executeHelpText(context)
|
||||
} else if (ret != null)
|
||||
throw Exception("Wrong return type! Must return a boolean or void. Return value: $ret")
|
||||
} catch (e: InvocationTargetException) {
|
||||
|
|
|
@ -41,6 +41,15 @@ object CommandUtils {
|
|||
else null
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the node as a probably-not-executable core command node or return null if it's an argument node.
|
||||
*
|
||||
* This method will work for any node as opposed to [CommandUtils.coreCommand].
|
||||
*/
|
||||
fun <TP : Command2Sender> CommandNode<TP>.coreCommandNoOp(): CoreCommandNode<TP, NoOpSubcommandData>? {
|
||||
return coreCommand()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the node as an executable core command node or returns null if it's a no-op node.
|
||||
*
|
||||
|
@ -76,11 +85,11 @@ object CommandUtils {
|
|||
@Suppress("UNCHECKED_CAST")
|
||||
fun <TP : Command2Sender, TC : ICommand2<TP>> CommandNode<TP>.subcommandData(): SubcommandData<TC, TP>? {
|
||||
return coreArgument()?.commandData as SubcommandData<TC, TP>?
|
||||
?: coreCommand<_, SubcommandData<TC, TP>>()?.data
|
||||
?: coreExecutable<TP, TC>()?.data
|
||||
}
|
||||
|
||||
fun <TP : Command2Sender> CommandNode<TP>.subcommandDataNoOp(): NoOpSubcommandData? {
|
||||
return subcommandData() ?: coreCommand<_, NoOpSubcommandData>()?.data
|
||||
return subcommandData() ?: coreCommandNoOp()?.data
|
||||
}
|
||||
|
||||
fun Class<*>.isEasilyRepresentable(): Boolean {
|
||||
|
|
|
@ -80,11 +80,4 @@ class SubcommandData<TC : ICommand2<*>, TP : Command2Sender>(
|
|||
method.isAccessible = true
|
||||
return method.invoke(command, sender, *args)
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the help text to the specified sender.
|
||||
*/
|
||||
fun sendHelpText(sender: TP) {
|
||||
sender.sendMessage(getHelpText(sender))
|
||||
}
|
||||
}
|
|
@ -46,9 +46,13 @@ class Command2MCTest {
|
|||
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(NoArgTestCommand)
|
||||
assertEquals("No sender parameter for method '${ErroringTestCommand::class.java.getMethod("def")}'", assertFails { MainPlugin.instance.registerCommand(ErroringTestCommand) }.message)
|
||||
MainPlugin.instance.registerCommand(MultiArgTestCommand)
|
||||
|
||||
MainPlugin.instance.registerCommand(TestNoMainCommand1)
|
||||
MainPlugin.instance.registerCommand(TestNoMainCommand2)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -72,19 +76,33 @@ class Command2MCTest {
|
|||
val user = ChromaGamerBase.getUser(UUID.randomUUID().toString(), TBMCPlayer::class.java)
|
||||
user.playerName = "TestPlayer"
|
||||
val sender = object : Command2MCSender(user, Channel.globalChat, user) {
|
||||
private var messageReceived: String? = null
|
||||
private var allowMessageReceive = false
|
||||
|
||||
override fun sendMessage(message: String) {
|
||||
error(message)
|
||||
if (allowMessageReceive) {
|
||||
messageReceived = message
|
||||
} else {
|
||||
error(message)
|
||||
}
|
||||
}
|
||||
|
||||
override fun sendMessage(message: Array<String>) {
|
||||
error(message.joinToString("\n"))
|
||||
sendMessage(message.joinToString("\n"))
|
||||
}
|
||||
|
||||
fun withMessageReceive(action: () -> Unit): String? {
|
||||
allowMessageReceive = true
|
||||
action()
|
||||
allowMessageReceive = false
|
||||
return messageReceived
|
||||
}
|
||||
}
|
||||
runCommand(sender, "/test hmm", TestCommand, "hmm")
|
||||
runCommand(sender, "/noargtest", NoArgTestCommand, "TestPlayer")
|
||||
assertFails { ButtonPlugin.command2MC.handleCommand(sender, "/noargtest failing") }
|
||||
runFailingCommand(sender, "/erroringtest")
|
||||
runCommand(sender, "/multiargtest hmm mhm", MultiArgTestCommand, "hmmmhm")
|
||||
runCommand(sender, "/multiargtest test hmm mhm", MultiArgTestCommand, "hmmmhm")
|
||||
runCommand(sender, "/multiargtest test2 true 19", MultiArgTestCommand, "true 19")
|
||||
|
||||
runCommand(sender, "/multiargtest testoptional", MultiArgTestCommand, "false")
|
||||
|
@ -95,7 +113,19 @@ class Command2MCTest {
|
|||
|
||||
runCommand(sender, "/test plugin Chroma-Core", TestCommand, "Chroma-Core")
|
||||
assertFails { ButtonPlugin.command2MC.handleCommand(sender, "/test playerfail TestPlayer") }
|
||||
// TODO: Add expected missing params
|
||||
|
||||
assertEquals("Test command\n" +
|
||||
"Used for testing\n" +
|
||||
"§6---- Subcommands ----\n" +
|
||||
"/test playerfail\n" +
|
||||
"/test plugin", sender.withMessageReceive { ButtonPlugin.command2MC.handleCommand(sender, "/test") })
|
||||
|
||||
runCommand(sender, "/some test cmd", TestNoMainCommand1, "TestPlayer")
|
||||
runCommand(sender, "/some another cmd", TestNoMainCommand2, "TestPlayer")
|
||||
|
||||
assertEquals("§6---- Subcommands ----\n" +
|
||||
"/some test cmd\n" +
|
||||
"/some another cmd", sender.withMessageReceive { ButtonPlugin.command2MC.handleCommand(sender, "/some") })
|
||||
}
|
||||
|
||||
private fun runCommand(sender: Command2MCSender, command: String, obj: ITestCommand2MC, expected: String) {
|
||||
|
@ -107,7 +137,7 @@ class Command2MCTest {
|
|||
assert(!ButtonPlugin.command2MC.handleCommand(sender, command)) { "Could execute command $command that shouldn't work" }
|
||||
}
|
||||
|
||||
@CommandClass
|
||||
@CommandClass(helpText = ["Test command", "Used for testing"])
|
||||
object TestCommand : ICommand2MC(), ITestCommand2MC {
|
||||
override var testCommandReceived: String? = null
|
||||
|
||||
|
@ -154,7 +184,7 @@ class Command2MCTest {
|
|||
override var testCommandReceived: String? = null
|
||||
|
||||
@Command2.Subcommand
|
||||
fun def(sender: Command2MCSender, test: String, test2: String) {
|
||||
fun test(sender: Command2MCSender, test: String, test2: String) {
|
||||
testCommandReceived = test + test2
|
||||
}
|
||||
|
||||
|
@ -174,6 +204,28 @@ class Command2MCTest {
|
|||
}
|
||||
}
|
||||
|
||||
@CommandClass(path = "some test cmd")
|
||||
object TestNoMainCommand1 : ICommand2MC(), ITestCommand2MC {
|
||||
override var testCommandReceived: String? = null
|
||||
|
||||
@Command2.Subcommand
|
||||
override fun def(sender: Command2MCSender): Boolean {
|
||||
testCommandReceived = sender.name
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@CommandClass(path = "some another cmd")
|
||||
object TestNoMainCommand2 : ICommand2MC(), ITestCommand2MC {
|
||||
override var testCommandReceived: String? = null
|
||||
|
||||
@Command2.Subcommand
|
||||
override fun def(sender: Command2MCSender): Boolean {
|
||||
testCommandReceived = sender.name
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private var initialized = false
|
||||
}
|
||||
|
|
|
@ -25,6 +25,14 @@ buttondevteam:
|
|||
test2:
|
||||
method: test2()
|
||||
params: "btest ntest"
|
||||
TestNoMainCommand1:
|
||||
def:
|
||||
method: def()
|
||||
params: ''
|
||||
TestNoMainCommand2:
|
||||
def:
|
||||
method: def()
|
||||
params: ''
|
||||
core:
|
||||
ComponentCommand:
|
||||
def:
|
||||
|
|
Loading…
Reference in a new issue