diff --git a/pom.xml b/pom.xml
index 2bb146a..49f8e71 100644
--- a/pom.xml
+++ b/pom.xml
@@ -63,6 +63,4 @@
provided
-
-
\ No newline at end of file
diff --git a/src/main/kotlin/com/qrakn/honcho/Honcho.kt b/src/main/kotlin/com/qrakn/honcho/Honcho.kt
index 7033aea..98ec45c 100644
--- a/src/main/kotlin/com/qrakn/honcho/Honcho.kt
+++ b/src/main/kotlin/com/qrakn/honcho/Honcho.kt
@@ -1,9 +1,11 @@
package com.qrakn.honcho
+import com.qrakn.honcho.command.CommandOption
import com.qrakn.honcho.command.adapter.CommandTypeAdapter
-import com.qrakn.honcho.command.adapter.impl.PlayerTypeAdapter
-import com.qrakn.honcho.command.adapter.impl.StringTypeAdapter
+import com.qrakn.honcho.command.adapter.impl.*
import org.bukkit.ChatColor
+import org.bukkit.GameMode
+import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
import org.bukkit.plugin.java.JavaPlugin
@@ -13,8 +15,15 @@ class Honcho(val plugin: JavaPlugin) {
var noPermissionMessage = "${ChatColor.RED}You don't have permission to do this."
init {
- registerTypeAdapter(String::class.java, StringTypeAdapter())
+ registerTypeAdapter(Boolean::class.java, BooleanTypeAdapter())
+ registerTypeAdapter(ChatColor::class.java, ChatColorTypeAdapter())
+ registerTypeAdapter(Double::class.java, DoubleTypeAdapter())
+ registerTypeAdapter(GameMode::class.java, GameModeTypeAdapter())
+ registerTypeAdapter(Integer::class.java, IntegerTypeAdapter())
+ registerTypeAdapter(OfflinePlayer::class.java, OfflinePlayerTypeAdapter())
+ registerTypeAdapter(CommandOption::class.java, CommandOptionTypeAdapter())
registerTypeAdapter(Player::class.java, PlayerTypeAdapter())
+ registerTypeAdapter(String::class.java, StringTypeAdapter())
}
fun registerCommand(command: Any) {
diff --git a/src/main/kotlin/com/qrakn/honcho/HonchoExecutor.kt b/src/main/kotlin/com/qrakn/honcho/HonchoExecutor.kt
index 4f19cf6..5e02443 100644
--- a/src/main/kotlin/com/qrakn/honcho/HonchoExecutor.kt
+++ b/src/main/kotlin/com/qrakn/honcho/HonchoExecutor.kt
@@ -2,6 +2,7 @@ package com.qrakn.honcho
import com.qrakn.honcho.command.CPL
import com.qrakn.honcho.command.CommandMeta
+import com.qrakn.honcho.command.CommandOption
import com.qrakn.honcho.command.adapter.CommandTypeAdapter
import com.qrakn.honcho.command.adapter.NonNullableCommandTypeAdapter
import org.apache.commons.lang.StringUtils
@@ -18,7 +19,7 @@ import org.bukkit.scheduler.BukkitRunnable
import java.lang.Exception
import java.lang.NullPointerException
import java.lang.reflect.Method
-import java.util.HashMap
+import java.util.*
internal class HonchoExecutor(private val honcho: Honcho) : CommandExecutor {
@@ -36,7 +37,7 @@ internal class HonchoExecutor(private val honcho: Honcho) : CommandExecutor {
}
}
- val binding = CommandBinding(methods.toTypedArray(), command)
+ val binding = CommandBinding(methods.toTypedArray(), meta, command)
for (label in HonchoCommand.getHierarchicalLabel(command.javaClass, ArrayList())) {
commands[label] = binding
@@ -57,10 +58,11 @@ internal class HonchoExecutor(private val honcho: Honcho) : CommandExecutor {
}
}
- fun execute(sender: CommandSender, command: Command, label: String, args: Array): Boolean {
+ fun execute(sender: CommandSender, command: Command, label: String, args: Array): Boolean {
val binding: CommandBinding = commands[label] ?: return false
val meta = binding.command.javaClass.getAnnotation(CommandMeta::class.java)
val instance = binding.command
+ var option = false
if (meta.permission.isNotEmpty() && !sender.hasPermission(meta.permission)) {
var message = honcho.noPermissionMessage
@@ -78,12 +80,22 @@ internal class HonchoExecutor(private val honcho: Honcho) : CommandExecutor {
override fun run() {
outer@ for (method in binding.methods) {
val parameters = method.parameters
+ var doContinue = true
if (parameters[0].type is Player && sender !is Player) continue
if (method.declaringClass != instance.javaClass) continue
if (method.parameterCount - 1 > args.size) {
- continue
+ for(param in parameters) {
+ if(param.type == CommandOption::class.java && method.parameterCount - 2 <= args.size) {
+ doContinue = false
+ break
+ }
+ }
+
+ if(doContinue) {
+ continue
+ }
}
/**
@@ -119,15 +131,23 @@ internal class HonchoExecutor(private val honcho: Honcho) : CommandExecutor {
}
try {
- val conversion = adapter.convert(input, parameter.type)
+ val conversion = adapter.convert(input!!, parameter.type)
if (conversion == null && adapter is NonNullableCommandTypeAdapter) {
throw NullPointerException()
}
+ if(conversion is CommandOption) {
+ if(!meta.options.contains(conversion.tag.toLowerCase())) {
+ sender.sendMessage("${ChatColor.RED}Unrecognized command option '-${conversion.tag}'!")
+ sender.sendMessage("${ChatColor.RED}Usage: ${command.usage}")
+ return
+ }
+ }
+
arguments.add(conversion)
} catch (exception: Exception) {
- if (!adapter.onException(exception, sender, input)) { // if exception not handled by adapter
+ if (!adapter.onException(exception, sender, input!!)) { // if exception not handled by adapter
sender.sendMessage("${ChatColor.RED}An error occurred (${exception.message}), please contact an administrator")
}
return
@@ -154,7 +174,7 @@ internal class HonchoExecutor(private val honcho: Honcho) : CommandExecutor {
return true
}
- override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean {
+ override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean {
return execute(sender, command, label, args)
}
@@ -176,7 +196,19 @@ internal class HonchoExecutor(private val honcho: Honcho) : CommandExecutor {
private fun getCommandUsage(label: String): String {
val command = commands[label]!!
val builder = StringBuilder("/").append(label)
- val arguments: MutableMap = HashMap()
+ val arguments: MutableMap = HashMap()
+
+ if(command.meta.options.isNotEmpty()) {
+ val options = ArrayList()
+
+ command.meta.options.forEach {
+ options.add("-" + it.toLowerCase())
+ }
+
+ builder.append(" [")
+ builder.append(StringUtils.join(options, ","))
+ builder.append("]")
+ }
for (method in command.methods) {
val parameters = method.parameters
@@ -191,24 +223,31 @@ internal class HonchoExecutor(private val honcho: Honcho) : CommandExecutor {
parameter.name
}
- if (!(argument.arguments.contains(name))) {
- argument.arguments.add(name)
- arguments[i - 1] = argument
+ if(parameter.type == CommandOption::class.java) {
+ arguments[i - 1] = null
+ } else {
+ if (argument != null) {
+ if (!(argument.arguments.contains(name))) {
+ argument.arguments.add(name)
+ arguments[i - 1] = argument
+ }
+ }
}
}
-
}
for (index in 0 until arguments.size) {
val argument = arguments[index]
- builder.append(" <").append(StringUtils.join(argument?.arguments, "/")).append(">")
+ if(argument != null) {
+ builder.append(" <").append(StringUtils.join(argument.arguments, "/")).append(">")
+ }
}
return builder.toString()
}
private inner class CommandArguments(val arguments: MutableList)
- internal inner class CommandBinding(val methods: Array, val command: Any)
+ internal inner class CommandBinding(val methods: Array, val meta: CommandMeta, val command: Any)
}
\ No newline at end of file
diff --git a/src/main/kotlin/com/qrakn/honcho/command/CommandMeta.kt b/src/main/kotlin/com/qrakn/honcho/command/CommandMeta.kt
index 3c27d30..6fdf43c 100644
--- a/src/main/kotlin/com/qrakn/honcho/command/CommandMeta.kt
+++ b/src/main/kotlin/com/qrakn/honcho/command/CommandMeta.kt
@@ -11,6 +11,7 @@ package com.qrakn.honcho.command
@Retention(AnnotationRetention.RUNTIME)
annotation class CommandMeta(
vararg val label: String,
+ val options: Array = [""],
val permission: String = "",
val description: String = "",
val subcommands: Boolean = false,
diff --git a/src/main/kotlin/com/qrakn/honcho/command/CommandOption.kt b/src/main/kotlin/com/qrakn/honcho/command/CommandOption.kt
new file mode 100644
index 0000000..ffa0f57
--- /dev/null
+++ b/src/main/kotlin/com/qrakn/honcho/command/CommandOption.kt
@@ -0,0 +1,3 @@
+package com.qrakn.honcho.command
+
+class CommandOption(val tag: String)
\ No newline at end of file
diff --git a/src/main/kotlin/com/qrakn/honcho/command/adapter/CommandTypeAdapter.kt b/src/main/kotlin/com/qrakn/honcho/command/adapter/CommandTypeAdapter.kt
index 23e144f..41e065c 100644
--- a/src/main/kotlin/com/qrakn/honcho/command/adapter/CommandTypeAdapter.kt
+++ b/src/main/kotlin/com/qrakn/honcho/command/adapter/CommandTypeAdapter.kt
@@ -4,6 +4,6 @@ import org.bukkit.command.CommandSender
import java.lang.Exception
interface CommandTypeAdapter {
- fun convert(string: String, type: Class): T
+ fun convert(string: String, type: Class): T?
fun onException(exception: Exception, sender: CommandSender, input: String): Boolean { return false }
}
\ No newline at end of file
diff --git a/src/main/kotlin/com/qrakn/honcho/command/adapter/impl/BooleanTypeAdapter.kt b/src/main/kotlin/com/qrakn/honcho/command/adapter/impl/BooleanTypeAdapter.kt
new file mode 100644
index 0000000..e7b2fa4
--- /dev/null
+++ b/src/main/kotlin/com/qrakn/honcho/command/adapter/impl/BooleanTypeAdapter.kt
@@ -0,0 +1,31 @@
+package com.qrakn.honcho.command.adapter.impl
+
+import com.qrakn.honcho.command.adapter.NonNullableCommandTypeAdapter
+import org.bukkit.ChatColor
+import org.bukkit.command.CommandSender
+import java.lang.Exception
+
+class BooleanTypeAdapter : NonNullableCommandTypeAdapter {
+ override fun convert(string: String, type: Class): T {
+ return type.cast(MAP[string.toLowerCase()])
+ }
+
+ override fun onException(exception: Exception, sender: CommandSender, input: String): Boolean {
+ sender.sendMessage("${ChatColor.RED}The value '$input' is not a boolean. ${ChatColor.GRAY}[yes, no]")
+ return true
+ }
+
+ companion object {
+ private val MAP = HashMap()
+
+ init {
+ MAP["true"] = true
+ MAP["on"] = true
+ MAP["yes"] = true
+
+ MAP["false"] = false
+ MAP["off"] = false
+ MAP["no"] = false
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/qrakn/honcho/command/adapter/impl/ChatColorTypeAdapter.kt b/src/main/kotlin/com/qrakn/honcho/command/adapter/impl/ChatColorTypeAdapter.kt
new file mode 100644
index 0000000..1a72444
--- /dev/null
+++ b/src/main/kotlin/com/qrakn/honcho/command/adapter/impl/ChatColorTypeAdapter.kt
@@ -0,0 +1,17 @@
+package com.qrakn.honcho.command.adapter.impl
+
+import com.qrakn.honcho.command.adapter.NonNullableCommandTypeAdapter
+import org.bukkit.ChatColor
+import org.bukkit.command.CommandSender
+import java.lang.Exception
+
+class ChatColorTypeAdapter : NonNullableCommandTypeAdapter {
+ override fun convert(string: String, type: Class): T? {
+ return type.cast(ChatColor.valueOf(string.toUpperCase()))
+ }
+
+ override fun onException(exception: Exception, sender: CommandSender, input: String): Boolean {
+ sender.sendMessage("${ChatColor.RED}The value '$input' is not a chatcolor. ${ChatColor.GRAY}[RED, DARK_RED]")
+ return true
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/qrakn/honcho/command/adapter/impl/CommandOptionTypeAdapter.kt b/src/main/kotlin/com/qrakn/honcho/command/adapter/impl/CommandOptionTypeAdapter.kt
new file mode 100644
index 0000000..721243e
--- /dev/null
+++ b/src/main/kotlin/com/qrakn/honcho/command/adapter/impl/CommandOptionTypeAdapter.kt
@@ -0,0 +1,17 @@
+package com.qrakn.honcho.command.adapter.impl
+
+import com.qrakn.honcho.command.CommandOption
+import com.qrakn.honcho.command.adapter.CommandTypeAdapter
+import org.bukkit.command.CommandSender
+
+class CommandOptionTypeAdapter : CommandTypeAdapter {
+ override fun convert(string: String, type: Class): T? {
+ return if (string.startsWith("-")) {
+ type.cast(CommandOption(string.toLowerCase().substring(1)))
+ } else null
+ }
+
+ override fun onException(exception: Exception, sender: CommandSender, input: String): Boolean {
+ return false
+ }
+}
diff --git a/src/main/kotlin/com/qrakn/honcho/command/adapter/impl/DoubleTypeAdapter.kt b/src/main/kotlin/com/qrakn/honcho/command/adapter/impl/DoubleTypeAdapter.kt
new file mode 100644
index 0000000..a5b6379
--- /dev/null
+++ b/src/main/kotlin/com/qrakn/honcho/command/adapter/impl/DoubleTypeAdapter.kt
@@ -0,0 +1,17 @@
+package com.qrakn.honcho.command.adapter.impl
+
+import com.qrakn.honcho.command.adapter.NonNullableCommandTypeAdapter
+import org.bukkit.ChatColor
+import org.bukkit.command.CommandSender
+import java.lang.Exception
+
+class DoubleTypeAdapter : NonNullableCommandTypeAdapter {
+ override fun convert(string: String, type: Class): T {
+ return type.cast(string.toDoubleOrNull())
+ }
+
+ override fun onException(exception: Exception, sender: CommandSender, input: String): Boolean {
+ sender.sendMessage("${ChatColor.RED}The value '$input' is not a double. ${ChatColor.GRAY}[2.0, 1.2, 1.5]")
+ return true
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/qrakn/honcho/command/adapter/impl/GameModeTypeAdapter.kt b/src/main/kotlin/com/qrakn/honcho/command/adapter/impl/GameModeTypeAdapter.kt
new file mode 100644
index 0000000..0028c9e
--- /dev/null
+++ b/src/main/kotlin/com/qrakn/honcho/command/adapter/impl/GameModeTypeAdapter.kt
@@ -0,0 +1,41 @@
+package com.qrakn.honcho.command.adapter.impl
+
+import com.qrakn.honcho.command.adapter.NonNullableCommandTypeAdapter
+import org.bukkit.ChatColor
+import org.bukkit.GameMode
+import org.bukkit.command.CommandSender
+import java.lang.Exception
+import java.util.*
+
+class GameModeTypeAdapter : NonNullableCommandTypeAdapter {
+ override fun convert(string: String, type: Class): T {
+ return type.cast(MAP[string.toLowerCase()])
+ }
+
+ override fun onException(exception: Exception, sender: CommandSender, input: String): Boolean {
+ sender.sendMessage("${ChatColor.RED}The value '$input' is not a gamemode. ${ChatColor.GRAY}[creative, 0, a]")
+ return true
+ }
+
+ companion object {
+ private val MAP = HashMap()
+
+ init {
+ MAP["c"] = GameMode.CREATIVE
+ MAP["creative"] = GameMode.CREATIVE
+ MAP["1"] = GameMode.CREATIVE
+
+ MAP["s"] = GameMode.SURVIVAL
+ MAP["survival"] = GameMode.SURVIVAL
+ MAP["0"] = GameMode.SURVIVAL
+
+ MAP["a"] = GameMode.ADVENTURE
+ MAP["adventure"] = GameMode.ADVENTURE
+ MAP["2"] = GameMode.ADVENTURE
+
+ MAP["sp"] = GameMode.SPECTATOR
+ MAP["spectator"] = GameMode.SPECTATOR
+ MAP["3"] = GameMode.SPECTATOR
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/qrakn/honcho/command/adapter/impl/IntegerTypeAdapter.kt b/src/main/kotlin/com/qrakn/honcho/command/adapter/impl/IntegerTypeAdapter.kt
new file mode 100644
index 0000000..6b91b46
--- /dev/null
+++ b/src/main/kotlin/com/qrakn/honcho/command/adapter/impl/IntegerTypeAdapter.kt
@@ -0,0 +1,17 @@
+package com.qrakn.honcho.command.adapter.impl
+
+import com.qrakn.honcho.command.adapter.NonNullableCommandTypeAdapter
+import org.bukkit.ChatColor
+import org.bukkit.command.CommandSender
+import java.lang.Exception
+
+class IntegerTypeAdapter : NonNullableCommandTypeAdapter {
+ override fun convert(string: String, type: Class): T {
+ return type.cast(Integer.parseInt(string))
+ }
+
+ override fun onException(exception: Exception, sender: CommandSender, input: String): Boolean {
+ sender.sendMessage("${ChatColor.RED}The value '$input' is not an integer. ${ChatColor.GRAY}[1, 2, 3]")
+ return true
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/qrakn/honcho/command/adapter/impl/OfflinePlayerTypeAdapter.kt b/src/main/kotlin/com/qrakn/honcho/command/adapter/impl/OfflinePlayerTypeAdapter.kt
new file mode 100644
index 0000000..9bb4bbe
--- /dev/null
+++ b/src/main/kotlin/com/qrakn/honcho/command/adapter/impl/OfflinePlayerTypeAdapter.kt
@@ -0,0 +1,18 @@
+package com.qrakn.honcho.command.adapter.impl
+
+import com.qrakn.honcho.command.adapter.NonNullableCommandTypeAdapter
+import org.bukkit.Bukkit
+import org.bukkit.ChatColor
+import org.bukkit.command.CommandSender
+import java.lang.Exception
+
+class OfflinePlayerTypeAdapter : NonNullableCommandTypeAdapter {
+ override fun convert(string: String, type: Class): T {
+ return type.cast(Bukkit.getOfflinePlayer(string))
+ }
+
+ override fun onException(exception: Exception, sender: CommandSender, input: String): Boolean {
+ sender.sendMessage("${ChatColor.RED}The player '$input' could not be found.")
+ return true
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/qrakn/honcho/command/example/ExampleCommand.kt b/src/main/kotlin/com/qrakn/honcho/command/example/ExampleCommand.kt
index d571773..24d4c16 100644
--- a/src/main/kotlin/com/qrakn/honcho/command/example/ExampleCommand.kt
+++ b/src/main/kotlin/com/qrakn/honcho/command/example/ExampleCommand.kt
@@ -1,23 +1,24 @@
package com.qrakn.honcho.command.example
+import com.qrakn.honcho.command.CPL
import com.qrakn.honcho.command.CommandMeta
+import com.qrakn.honcho.command.CommandOption
import org.bukkit.ChatColor
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
-@CommandMeta(label = ["example"], description = "Example command", subcommands = true)
+@CommandMeta(label = ["example"], options = ["s"], description = "Example command", subcommands = true)
open class ExampleCommand {
- fun execute(sender: CommandSender, player: Player?) {
+ fun execute(sender: CommandSender, option: CommandOption?, player: Player) {
+ sender.sendMessage("You poked ${player.name}.")
- if (player == null) {
- sender.sendMessage("${ChatColor.RED}Player not found.")
- return
+ if(option == null) {
+ player.sendMessage("${sender.name} poked you.")
+ } else {
+ player.sendMessage("Someone poked you, but who?")
}
- sender.sendMessage("You poked ${player.name}.")
-
- player.sendMessage("${sender.name} poked you.")
player.damage(0.0)
}
@@ -25,9 +26,7 @@ open class ExampleCommand {
inner class ExampleSubCommand : ExampleCommand() {
fun execute(sender: CommandSender) {
- sender.sendMessage("${ChatColor.RED}honcho v1.0-SNAPSHOT")
+ sender.sendMessage("${ChatColor.RED}honcho v1.3-SNAPSHOT")
}
-
}
-
}
\ No newline at end of file