diff --git a/core/src/main/kotlin/com/github/spigotbasics/core/command/BasicsCommand.kt b/core/src/main/kotlin/com/github/spigotbasics/core/command/BasicsCommand.kt index aeb53f91..2c547d74 100644 --- a/core/src/main/kotlin/com/github/spigotbasics/core/command/BasicsCommand.kt +++ b/core/src/main/kotlin/com/github/spigotbasics/core/command/BasicsCommand.kt @@ -19,6 +19,7 @@ import java.util.logging.Level class BasicsCommand internal constructor( var info: CommandInfo, private var executor: BasicsCommandExecutor?, + private var tabCompleter: BasicsTabCompleter?, val coreMessages: CoreMessages, val messageFactory: MessageFactory, ) : @@ -34,11 +35,6 @@ class BasicsCommand internal constructor( permissionMessage = info.permissionMessage.tagParsed("permission", permString).toLegacyString() } -// private val customUsageMessage = messageFactory.createMessage( -// "Invalid command usage.", -// "Usage: " -// ).tagParsed("usage", usage).tagParsed("command", name) - override fun execute( sender: CommandSender, commandLabel: String, @@ -108,8 +104,8 @@ class BasicsCommand internal constructor( args = args.toMutableList(), location = location, ) - if (executor == null) return mutableListOf() - val result = executor!!.tabComplete(context) + if (tabCompleter == null) return mutableListOf() + val result = tabCompleter!!.tabComplete(context) return result ?: super.tabComplete(sender, alias, args, location) } @@ -120,5 +116,6 @@ class BasicsCommand internal constructor( */ fun disableExecutor() { executor = null + tabCompleter = null } } diff --git a/core/src/main/kotlin/com/github/spigotbasics/core/command/BasicsCommandBuilder.kt b/core/src/main/kotlin/com/github/spigotbasics/core/command/BasicsCommandBuilder.kt index afeb3e19..c0c4c4cb 100644 --- a/core/src/main/kotlin/com/github/spigotbasics/core/command/BasicsCommandBuilder.kt +++ b/core/src/main/kotlin/com/github/spigotbasics/core/command/BasicsCommandBuilder.kt @@ -14,6 +14,7 @@ class BasicsCommandBuilder( private var usage: String = "" private var aliases: List = emptyList() private var executor: BasicsCommandExecutor? = null + private var tabCompleter: BasicsTabCompleter? = null fun description(description: String) = apply { this.description = description } @@ -29,6 +30,8 @@ class BasicsCommandBuilder( fun executor(executor: BasicsCommandExecutor) = apply { this.executor = executor } + fun tabCompleter(tabCompleter: BasicsTabCompleter) = apply { this.tabCompleter = tabCompleter } + fun executor(executor: (BasicsCommandContext) -> CommandResult?) = apply { this.executor = @@ -39,6 +42,16 @@ class BasicsCommandBuilder( } } + fun tabCompleter(tabCompleter: (BasicsCommandContext) -> MutableList?) = + apply { + this.tabCompleter = + object : BasicsTabCompleter { + override fun tabComplete(context: BasicsCommandContext): MutableList? { + return tabCompleter(context) + } + } + } + fun register(): BasicsCommand { val command = build() module.commandManager.registerCommand(command) @@ -56,10 +69,11 @@ class BasicsCommandBuilder( aliases = aliases, ) return BasicsCommand( - info, - executor ?: error("Executor must be set"), - module.plugin.messages, - module.plugin.messageFactory, + info = info, + executor = executor ?: error("Executor must be set"), + tabCompleter = tabCompleter ?: executor, + coreMessages = module.plugin.messages, + messageFactory = module.plugin.messageFactory, ) } } diff --git a/core/src/main/kotlin/com/github/spigotbasics/core/command/BasicsCommandContextHandler.kt b/core/src/main/kotlin/com/github/spigotbasics/core/command/BasicsCommandContextHandler.kt new file mode 100644 index 00000000..3302d725 --- /dev/null +++ b/core/src/main/kotlin/com/github/spigotbasics/core/command/BasicsCommandContextHandler.kt @@ -0,0 +1,79 @@ +package com.github.spigotbasics.core.command + +import com.github.spigotbasics.core.messages.CoreMessages +import com.github.spigotbasics.core.messages.MessageFactory +import org.bukkit.Bukkit +import org.bukkit.command.CommandSender +import org.bukkit.entity.Player +import org.bukkit.inventory.ItemStack +import org.bukkit.permissions.Permission + +abstract class BasicsCommandContextHandler( + val coreMessages: CoreMessages, + val messageFactory: MessageFactory, +) { + @Throws(BasicsCommandException::class) + fun requirePlayer(name: String): Player { + val player = Bukkit.getPlayer(name) + if (player == null) { + throw BasicsCommandException(CommandResult.playerNotFound(name)) + } + return player + } + + @Throws(BasicsCommandException::class) + fun notFromConsole(sender: CommandSender): Player { + if (sender !is Player) { + throw CommandResult.NOT_FROM_CONSOLE.asException() + } + return sender + } + + // TODO: In 99% of cases, we should just use requirePlayer(CommandSender) instead of this method + @Throws(BasicsCommandException::class) + fun requirePlayerOrMustSpecifyPlayerFromConsole(sender: CommandSender): Player { + val player = sender as? Player + if (player == null) { + throw CommandResult.MUST_BE_PLAYER_OR_SPECIFY_PLAYER_FROM_CONSOLE.asException() + } + return player + } + + @Throws(BasicsCommandException::class) + fun failIfFlagsLeft(context: BasicsCommandContext) { + if (context.flags.isEmpty()) return + throw CommandResult.unknownFlag(context.flags[0]).asException() + } + + @Throws(BasicsCommandException::class) + fun failInvalidArgument(argument: String): CommandResult { + throw CommandResult.invalidArgument(argument).asException() + } + + fun requirePermission( + sender: CommandSender, + permission: Permission, + ) { + if (!sender.hasPermission(permission)) { + throw CommandResult.noPermission(permission).asException() + } + } + + // @Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS") + + fun requireItemInHand(player: Player): ItemStack { + val item = player.inventory.itemInMainHand + if (item.type.isAir) { + throw CommandResult.NO_ITEM_IN_HAND.asException() + } + return item + } + + fun requireItemInHandOther(player: Player): ItemStack { + val item = player.inventory.itemInMainHand + if (item.type.isAir) { + throw CommandResult.noItemInHandOthers(player).asException() + } + return item + } +} diff --git a/core/src/main/kotlin/com/github/spigotbasics/core/command/BasicsCommandExecutor.kt b/core/src/main/kotlin/com/github/spigotbasics/core/command/BasicsCommandExecutor.kt index 0d2009a2..d77277e7 100644 --- a/core/src/main/kotlin/com/github/spigotbasics/core/command/BasicsCommandExecutor.kt +++ b/core/src/main/kotlin/com/github/spigotbasics/core/command/BasicsCommandExecutor.kt @@ -3,86 +3,16 @@ package com.github.spigotbasics.core.command import com.github.spigotbasics.core.messages.CoreMessages import com.github.spigotbasics.core.messages.MessageFactory import com.github.spigotbasics.core.module.BasicsModule -import org.bukkit.Bukkit -import org.bukkit.command.CommandSender -import org.bukkit.entity.Player -import org.bukkit.inventory.ItemStack -import org.bukkit.permissions.Permission -abstract class BasicsCommandExecutor(module: BasicsModule) { - protected val coreMessages: CoreMessages = module.plugin.messages - protected val messageFactory: MessageFactory = module.plugin.messageFactory +abstract class BasicsCommandExecutor( + coreMessages: CoreMessages, + messageFactory: MessageFactory, +) : BasicsCommandContextHandler(coreMessages, messageFactory), BasicsTabCompleter { + constructor(module: BasicsModule) : this(module.coreMessages, module.messageFactory) abstract fun execute(context: BasicsCommandContext): CommandResult? - open fun tabComplete(context: BasicsCommandContext): MutableList? { + override fun tabComplete(context: BasicsCommandContext): MutableList? { return null } - - // TODO: Move these methods into own CommandParser object - - @Throws(BasicsCommandException::class) - fun requirePlayer(name: String): Player { - val player = Bukkit.getPlayer(name) - if (player == null) { - throw BasicsCommandException(CommandResult.playerNotFound(name)) - } - return player - } - - @Throws(BasicsCommandException::class) - fun notFromConsole(sender: CommandSender): Player { - if (sender !is Player) { - throw CommandResult.NOT_FROM_CONSOLE.asException() - } - return sender - } - - // TODO: In 99% of cases, we should just use requirePlayer(CommandSender) instead of this method - @Throws(BasicsCommandException::class) - fun requirePlayerOrMustSpecifyPlayerFromConsole(sender: CommandSender): Player { - val player = sender as? Player - if (player == null) { - throw CommandResult.MUST_BE_PLAYER_OR_SPECIFY_PLAYER_FROM_CONSOLE.asException() - } - return player - } - - @Throws(BasicsCommandException::class) - fun failIfFlagsLeft(context: BasicsCommandContext) { - if (context.flags.isEmpty()) return - throw CommandResult.unknownFlag(context.flags[0]).asException() - } - - @Throws(BasicsCommandException::class) - fun failInvalidArgument(argument: String): CommandResult { - throw CommandResult.invalidArgument(argument).asException() - } - - fun requirePermission( - sender: CommandSender, - permission: Permission, - ) { - if (!sender.hasPermission(permission)) { - throw CommandResult.noPermission(permission).asException() - } - } - - // @Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS") - - fun requireItemInHand(player: Player): ItemStack { - val item = player.inventory.itemInMainHand - if (item.type.isAir) { - throw CommandResult.NO_ITEM_IN_HAND.asException() - } - return item - } - - fun requireItemInHandOther(player: Player): ItemStack { - val item = player.inventory.itemInMainHand - if (item.type.isAir) { - throw CommandResult.noItemInHandOthers(player).asException() - } - return item - } } diff --git a/core/src/main/kotlin/com/github/spigotbasics/core/command/BasicsTabCompleter.kt b/core/src/main/kotlin/com/github/spigotbasics/core/command/BasicsTabCompleter.kt new file mode 100644 index 00000000..da992224 --- /dev/null +++ b/core/src/main/kotlin/com/github/spigotbasics/core/command/BasicsTabCompleter.kt @@ -0,0 +1,5 @@ +package com.github.spigotbasics.core.command + +interface BasicsTabCompleter { + fun tabComplete(context: BasicsCommandContext): MutableList? +}