Fixed getSubcommands() and other command fixes
- Command2MC tab completion still awaits - but then that might be all that's left before testing
This commit is contained in:
parent
30a2fe0b68
commit
8616ecbefc
12 changed files with 189 additions and 167 deletions
|
@ -14,7 +14,7 @@ import java.util.Optional;
|
||||||
@CommandClass
|
@CommandClass
|
||||||
public class ChromaCommand extends ICommand2MC {
|
public class ChromaCommand extends ICommand2MC {
|
||||||
public ChromaCommand() {
|
public ChromaCommand() {
|
||||||
manager.addParamConverter(ButtonPlugin.class, name ->
|
getManager().addParamConverter(ButtonPlugin.class, name ->
|
||||||
(ButtonPlugin) Optional.ofNullable(Bukkit.getPluginManager().getPlugin(name))
|
(ButtonPlugin) Optional.ofNullable(Bukkit.getPluginManager().getPlugin(name))
|
||||||
.filter(plugin -> plugin instanceof ButtonPlugin).orElse(null),
|
.filter(plugin -> plugin instanceof ButtonPlugin).orElse(null),
|
||||||
"No Chroma plugin found by that name.", () -> Arrays.stream(Bukkit.getPluginManager().getPlugins())
|
"No Chroma plugin found by that name.", () -> Arrays.stream(Bukkit.getPluginManager().getPlugins())
|
||||||
|
|
|
@ -57,7 +57,7 @@ class MainPlugin : ButtonPlugin() {
|
||||||
public override fun pluginEnable() {
|
public override fun pluginEnable() {
|
||||||
instance = this
|
instance = this
|
||||||
val pdf = description
|
val pdf = description
|
||||||
if (!setupPermissions()) throw NullPointerException("No permission plugin found!")
|
setupPermissions()
|
||||||
if (!setupEconomy()) //Though Essentials always provides economy, but we don't require Essentials
|
if (!setupEconomy()) //Though Essentials always provides economy, but we don't require Essentials
|
||||||
logger.warning("No economy plugin found! Components using economy will not be registered.")
|
logger.warning("No economy plugin found! Components using economy will not be registered.")
|
||||||
saveConfig()
|
saveConfig()
|
||||||
|
@ -134,9 +134,8 @@ class MainPlugin : ButtonPlugin() {
|
||||||
logger.info("Player data saved.")
|
logger.info("Player data saved.")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupPermissions(): Boolean {
|
private fun setupPermissions() {
|
||||||
permission = setupProvider(Permission::class.java)
|
permission = setupProvider(Permission::class.java) ?: throw NullPointerException("No permission plugin found!")
|
||||||
return permission != null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupEconomy(): Boolean {
|
private fun setupEconomy(): Boolean {
|
||||||
|
@ -159,8 +158,7 @@ class MainPlugin : ButtonPlugin() {
|
||||||
companion object {
|
companion object {
|
||||||
lateinit var instance: MainPlugin
|
lateinit var instance: MainPlugin
|
||||||
|
|
||||||
@JvmField
|
lateinit var permission: Permission
|
||||||
var permission: Permission? = null
|
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
var ess: Essentials? = null
|
var ess: Essentials? = null
|
||||||
|
|
|
@ -42,7 +42,4 @@ class PrimeRestartCommand : ICommand2MC() {
|
||||||
Bukkit.spigot().restart()
|
Bukkit.spigot().restart()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -77,7 +77,7 @@ abstract class Component<TP : JavaPlugin> {
|
||||||
* @param command Custom coded command class
|
* @param command Custom coded command class
|
||||||
*/
|
*/
|
||||||
fun registerCommand(command: ICommand2MC) {
|
fun registerCommand(command: ICommand2MC) {
|
||||||
if (plugin is ButtonPlugin) command.registerToPlugin(plugin as ButtonPlugin)
|
if (plugin is ButtonPlugin) command.registerToPlugin(plugin as ButtonPlugin) // TODO: Require ButtonPlugin
|
||||||
command.registerToComponent(this)
|
command.registerToComponent(this)
|
||||||
ButtonPlugin.command2MC.registerCommand(command)
|
ButtonPlugin.command2MC.registerCommand(command)
|
||||||
}
|
}
|
||||||
|
@ -102,8 +102,7 @@ abstract class Component<TP : JavaPlugin> {
|
||||||
*/
|
*/
|
||||||
fun getConfigMap(key: String, defaultProvider: Map<String, Consumer<IHaveConfig>>): Map<String, IHaveConfig> {
|
fun getConfigMap(key: String, defaultProvider: Map<String, Consumer<IHaveConfig>>): Map<String, IHaveConfig> {
|
||||||
val c: ConfigurationSection = config.config
|
val c: ConfigurationSection = config.config
|
||||||
var cs = c.getConfigurationSection(key)
|
val cs = c.getConfigurationSection(key) ?: c.createSection(key)
|
||||||
if (cs == null) cs = c.createSection(key)
|
|
||||||
val res = cs.getValues(false).entries.stream()
|
val res = cs.getValues(false).entries.stream()
|
||||||
.filter { (_, value) -> value is ConfigurationSection }
|
.filter { (_, value) -> value is ConfigurationSection }
|
||||||
.collect(Collectors.toMap(
|
.collect(Collectors.toMap(
|
||||||
|
|
|
@ -133,13 +133,22 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender>(
|
||||||
* @param command The command to register
|
* @param command The command to register
|
||||||
* @return The Brigadier command node if you need it for something (like tab completion)
|
* @return The Brigadier command node if you need it for something (like tab completion)
|
||||||
*/
|
*/
|
||||||
protected fun registerCommandSuper(command: TC): LiteralCommandNode<TP> {
|
protected fun registerCommandSuper(command: TC): CoreCommandNode<TP, *> {
|
||||||
var mainCommandNode: LiteralCommandNode<TP>? = null
|
var mainCommandNode: CoreCommandNode<TP, *>? = null
|
||||||
for (meth in command.javaClass.methods) {
|
for (meth in command.javaClass.methods) {
|
||||||
val ann = meth.getAnnotation(Subcommand::class.java) ?: continue
|
val ann = meth.getAnnotation(Subcommand::class.java) ?: continue
|
||||||
val fullPath = command.commandPath + CommandUtils.getCommandPath(meth.name, ' ')
|
val fullPath = command.commandPath + CommandUtils.getCommandPath(meth.name, ' ')
|
||||||
val (lastNode, mainNode, remainingPath) = registerNodeFromPath(fullPath)
|
val (lastNode, mainNode, remainingPath) = registerNodeFromPath(fullPath)
|
||||||
lastNode.addChild(getExecutableNode(meth, command, ann, remainingPath, CommandArgumentHelpManager(command), fullPath))
|
lastNode.addChild(
|
||||||
|
getExecutableNode(
|
||||||
|
meth,
|
||||||
|
command,
|
||||||
|
ann,
|
||||||
|
remainingPath,
|
||||||
|
CommandArgumentHelpManager(command),
|
||||||
|
fullPath
|
||||||
|
)
|
||||||
|
)
|
||||||
if (mainCommandNode == null) mainCommandNode = mainNode
|
if (mainCommandNode == null) mainCommandNode = mainNode
|
||||||
else if (mainNode!!.name != mainCommandNode.name) {
|
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)
|
MainPlugin.instance.logger.warning("Multiple commands are defined in the same class! This is not supported. Class: " + command.javaClass.simpleName)
|
||||||
|
@ -193,16 +202,17 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender>(
|
||||||
* @return The last no-op node that can be used to register the executable node,
|
* @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)
|
* the main command node and the last part of the command path (that isn't registered yet)
|
||||||
*/
|
*/
|
||||||
private fun registerNodeFromPath(path: String): Triple<CommandNode<TP>, LiteralCommandNode<TP>?, String> {
|
private fun registerNodeFromPath(path: String): Triple<CommandNode<TP>, CoreCommandNode<TP, *>?, String> {
|
||||||
val split = path.split(" ")
|
val split = path.split(" ")
|
||||||
var parent: CommandNode<TP> = dispatcher.root
|
var parent: CommandNode<TP> = dispatcher.root
|
||||||
var mainCommand: LiteralCommandNode<TP>? = null
|
var mainCommand: CoreCommandNode<TP, *>? = null
|
||||||
split.forEachIndexed { i, part ->
|
split.forEachIndexed { i, part ->
|
||||||
val child = parent.getChild(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, getSubcommandList())
|
||||||
.executes(::executeHelpText).build().also { parent = it })
|
.executes(::executeHelpText).build().also { parent = it })
|
||||||
else parent = child
|
else parent = child
|
||||||
if (i == 0) mainCommand = parent as LiteralCommandNode<TP> // Has to be a literal, if not, well, error
|
if (i == 0) mainCommand =
|
||||||
|
parent as CoreCommandNode<TP, *> // Has to be our own literal node, if not, well, error
|
||||||
}
|
}
|
||||||
return Triple(parent, mainCommand, split.last())
|
return Triple(parent, mainCommand, split.last())
|
||||||
}
|
}
|
||||||
|
@ -362,9 +372,9 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender>(
|
||||||
*
|
*
|
||||||
* @return A set of command node objects containing the commands
|
* @return A set of command node objects containing the commands
|
||||||
*/
|
*/
|
||||||
val commandNodes: Set<CoreCommandNode<TP, TC, NoOpSubcommandData>>
|
val commandNodes: Set<CoreCommandNode<TP, NoOpSubcommandData>>
|
||||||
get() = dispatcher.root.children.stream()
|
get() = dispatcher.root.children.stream()
|
||||||
.map { node: CommandNode<TP> -> node.core<TP, TC, NoOpSubcommandData>() }
|
.map { node: CommandNode<TP> -> node.core<TP, NoOpSubcommandData>() }
|
||||||
.collect(Collectors.toUnmodifiableSet())
|
.collect(Collectors.toUnmodifiableSet())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -373,7 +383,7 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender>(
|
||||||
* @param command The exact name of the command
|
* @param command The exact name of the command
|
||||||
* @return A command node
|
* @return A command node
|
||||||
*/
|
*/
|
||||||
fun getCommandNode(command: String): CoreCommandNode<TP, TC, NoOpSubcommandData> { // TODO: What should this return? No-op? Executable? What's the use case?
|
fun getCommandNode(command: String): CoreCommandNode<TP, NoOpSubcommandData> { // TODO: What should this return? No-op? Executable? What's the use case?
|
||||||
return dispatcher.root.getChild(command).core()
|
return dispatcher.root.getChild(command).core()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,14 +401,14 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender>(
|
||||||
*
|
*
|
||||||
* @param condition The condition for removing a given command
|
* @param condition The condition for removing a given command
|
||||||
*/
|
*/
|
||||||
fun unregisterCommandIf(condition: Predicate<CoreCommandNode<TP, TC, SubcommandData<TC, TP>>>, nested: Boolean) {
|
fun unregisterCommandIf(condition: Predicate<CoreCommandNode<TP, SubcommandData<TC, TP>>>, nested: Boolean) {
|
||||||
dispatcher.root.children.removeIf { node -> node.coreExecutable<TP, TC>()?.let { condition.test(it) } ?: false }
|
dispatcher.root.children.removeIf { node -> node.coreExecutable<TP, TC>()?.let { condition.test(it) } ?: false }
|
||||||
if (nested) for (child in dispatcher.root.children) unregisterCommandIf(condition, child.core())
|
if (nested) for (child in dispatcher.root.children) unregisterCommandIf(condition, child.core())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unregisterCommandIf(
|
private fun unregisterCommandIf(
|
||||||
condition: Predicate<CoreCommandNode<TP, TC, SubcommandData<TC, TP>>>,
|
condition: Predicate<CoreCommandNode<TP, SubcommandData<TC, TP>>>,
|
||||||
root: CoreCommandNode<TP, TC, NoOpSubcommandData>
|
root: CoreCommandNode<TP, NoOpSubcommandData>
|
||||||
) {
|
) {
|
||||||
// TODO: Remvoe no-op nodes without children
|
// TODO: Remvoe no-op nodes without children
|
||||||
// Can't use getCoreChildren() here because the collection needs to be modifiable
|
// Can't use getCoreChildren() here because the collection needs to be modifiable
|
||||||
|
@ -408,8 +418,24 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender>(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all subcommands of the specified command. Only returns executable nodes.
|
* Get all subcommands of the specified command. Only returns executable nodes.
|
||||||
|
*
|
||||||
|
* @param mainCommand The command to get the subcommands of
|
||||||
|
* @param deep Whether to get all subcommands recursively or only the direct children
|
||||||
*/
|
*/
|
||||||
fun getSubcommands(mainCommand: LiteralCommandNode<TP>): List<CoreCommandNode<TP, TC, SubcommandData<TC, TP>>> {
|
fun getSubcommands(
|
||||||
return dispatcher.root.children.mapNotNull { it.coreExecutable<TP, TC>() } // TODO: Needs more depth
|
mainCommand: LiteralCommandNode<TP>,
|
||||||
|
deep: Boolean = true
|
||||||
|
): List<CoreCommandNode<TP, SubcommandData<TC, TP>>> {
|
||||||
|
return getSubcommands(mainCommand, deep, mainCommand.core())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSubcommands(
|
||||||
|
mainCommand: LiteralCommandNode<TP>,
|
||||||
|
deep: Boolean = true,
|
||||||
|
root: CoreCommandNode<TP, NoOpSubcommandData>
|
||||||
|
): List<CoreCommandNode<TP, SubcommandData<TC, TP>>> {
|
||||||
|
|
||||||
|
return root.children.mapNotNull { it.coreExecutable<TP, TC>() } +
|
||||||
|
if (deep) root.children.flatMap { getSubcommands(mainCommand, deep, it.core()) } else emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,6 +5,7 @@ import buttondevteam.lib.TBMCCoreAPI
|
||||||
import buttondevteam.lib.architecture.ButtonPlugin
|
import buttondevteam.lib.architecture.ButtonPlugin
|
||||||
import buttondevteam.lib.architecture.Component
|
import buttondevteam.lib.architecture.Component
|
||||||
import buttondevteam.lib.chat.commands.CommandUtils
|
import buttondevteam.lib.chat.commands.CommandUtils
|
||||||
|
import buttondevteam.lib.chat.commands.CommandUtils.coreExecutable
|
||||||
import buttondevteam.lib.chat.commands.MCCommandSettings
|
import buttondevteam.lib.chat.commands.MCCommandSettings
|
||||||
import buttondevteam.lib.chat.commands.SubcommandData
|
import buttondevteam.lib.chat.commands.SubcommandData
|
||||||
import buttondevteam.lib.player.ChromaGamerBase
|
import buttondevteam.lib.player.ChromaGamerBase
|
||||||
|
@ -29,7 +30,6 @@ import org.bukkit.entity.Player
|
||||||
import org.bukkit.event.Listener
|
import org.bukkit.event.Listener
|
||||||
import org.bukkit.permissions.Permission
|
import org.bukkit.permissions.Permission
|
||||||
import org.bukkit.permissions.PermissionDefault
|
import org.bukkit.permissions.PermissionDefault
|
||||||
import java.lang.reflect.Method
|
|
||||||
import java.lang.reflect.Parameter
|
import java.lang.reflect.Parameter
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.function.BiConsumer
|
import java.util.function.BiConsumer
|
||||||
|
@ -43,42 +43,24 @@ class Command2MC : Command2<ICommand2MC, Command2MCSender>('/', true), Listener
|
||||||
* @param command The command to register
|
* @param command The command to register
|
||||||
*/
|
*/
|
||||||
override fun registerCommand(command: ICommand2MC) {
|
override fun registerCommand(command: ICommand2MC) {
|
||||||
/*String mainpath;
|
|
||||||
var plugin = command.getPlugin();
|
|
||||||
{
|
|
||||||
String cpath = command.getCommandPath();
|
|
||||||
int i = cpath.indexOf(' ');
|
|
||||||
mainpath = cpath.substring(0, i == -1 ? cpath.length() : i);
|
|
||||||
}*/
|
|
||||||
val commandNode = super.registerCommandSuper(command)
|
val commandNode = super.registerCommandSuper(command)
|
||||||
val bcmd = registerOfficially(command, commandNode)
|
val bcmd = registerOfficially(command, commandNode)
|
||||||
if (bcmd != null) // TODO: Support aliases
|
if (bcmd != null) // TODO: Support aliases
|
||||||
super.registerCommandSuper(command)
|
super.registerCommandSuper(command)
|
||||||
val perm = "chroma.command." + command.commandPath.replace(' ', '.')
|
val permPrefix = "chroma.command."
|
||||||
if (Bukkit.getPluginManager().getPermission(perm) == null) //Check needed for plugin reset
|
//Allow commands by default, it will check mod-only
|
||||||
Bukkit.getPluginManager().addPermission(Permission(perm,
|
val nodes = commandNode.coreExecutable<Command2MCSender, ICommand2MC>()
|
||||||
PermissionDefault.TRUE)) //Allow commands by default, it will check mod-only
|
?.let { getSubcommands(commandNode) + it } ?: getSubcommands(commandNode)
|
||||||
for (node in getSubcommands(commandNode)) {
|
for (node in nodes) {
|
||||||
if (path.length > 0) {
|
val subperm = permPrefix + node.data.fullPath.replace(' ', '.')
|
||||||
val subperm = perm + path
|
if (Bukkit.getPluginManager().getPermission(subperm) == null) //Check needed for plugin reset
|
||||||
if (Bukkit.getPluginManager().getPermission(subperm) == null) //Check needed for plugin reset
|
Bukkit.getPluginManager().addPermission(Permission(subperm, PermissionDefault.TRUE))
|
||||||
Bukkit.getPluginManager().addPermission(
|
|
||||||
Permission(
|
|
||||||
subperm,
|
|
||||||
PermissionDefault.TRUE
|
|
||||||
)
|
|
||||||
) //Allow commands by default, it will check mod-only
|
|
||||||
}
|
|
||||||
val pg = permGroup(node.data)
|
val pg = permGroup(node.data)
|
||||||
if (pg.isEmpty()) continue
|
if (pg.isEmpty()) continue
|
||||||
val permGroup = "chroma.$pg"
|
val permGroup = "chroma.$pg"
|
||||||
|
//Do not allow any commands that belong to a group by default
|
||||||
if (Bukkit.getPluginManager().getPermission(permGroup) == null) //It may occur multiple times
|
if (Bukkit.getPluginManager().getPermission(permGroup) == null) //It may occur multiple times
|
||||||
Bukkit.getPluginManager().addPermission(
|
Bukkit.getPluginManager().addPermission(Permission(permGroup, PermissionDefault.OP))
|
||||||
Permission(
|
|
||||||
permGroup,
|
|
||||||
PermissionDefault.OP
|
|
||||||
)
|
|
||||||
) //Do not allow any commands that belong to a group
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +93,7 @@ class Command2MC : Command2<ICommand2MC, Command2MCSender>('/', true), Listener
|
||||||
/**
|
/**
|
||||||
* Returns the first group found in the hierarchy starting from the command method **or** the mod group if *any* of the superclasses are mod only.
|
* Returns the first group found in the hierarchy starting from the command method **or** the mod group if *any* of the superclasses are mod only.
|
||||||
*
|
*
|
||||||
* @param method The subcommand to check
|
* @param data The data of the subcommand to check
|
||||||
* @return The permission group for the subcommand or empty string
|
* @return The permission group for the subcommand or empty string
|
||||||
*/
|
*/
|
||||||
private fun permGroup(data: SubcommandData<ICommand2MC, Command2MCSender>): String {
|
private fun permGroup(data: SubcommandData<ICommand2MC, Command2MCSender>): String {
|
||||||
|
@ -170,7 +152,8 @@ class Command2MC : Command2<ICommand2MC, Command2MCSender>('/', true), Listener
|
||||||
val i = commandline.indexOf(' ')
|
val i = commandline.indexOf(' ')
|
||||||
val mainpath = commandline.substring(1, if (i == -1) commandline.length else i) //Without the slash
|
val mainpath = commandline.substring(1, if (i == -1) commandline.length else i) //Without the slash
|
||||||
//Our commands aren't PluginCommands, unless it's specified in the plugin.yml
|
//Our commands aren't PluginCommands, unless it's specified in the plugin.yml
|
||||||
return if ((!checkPlugin || (MainPlugin.instance.prioritizeCustomCommands.get() == true))
|
// So we need to handle the command if it's not a plugin command or if it's a plugin command, but for a ButtonPlugin
|
||||||
|
return if (!checkPlugin || MainPlugin.instance.prioritizeCustomCommands.get()
|
||||||
|| Bukkit.getPluginCommand(mainpath)?.let { it.plugin is ButtonPlugin } != false
|
|| Bukkit.getPluginCommand(mainpath)?.let { it.plugin is ButtonPlugin } != false
|
||||||
)
|
)
|
||||||
super.handleCommand(sender, commandline) else false
|
super.handleCommand(sender, commandline) else false
|
||||||
|
@ -178,28 +161,30 @@ class Command2MC : Command2<ICommand2MC, Command2MCSender>('/', true), Listener
|
||||||
|
|
||||||
private var shouldRegisterOfficially = true
|
private var shouldRegisterOfficially = true
|
||||||
private fun registerOfficially(command: ICommand2MC, node: LiteralCommandNode<Command2MCSender>): Command? {
|
private fun registerOfficially(command: ICommand2MC, node: LiteralCommandNode<Command2MCSender>): Command? {
|
||||||
return if (!shouldRegisterOfficially || command.plugin == null) null else try {
|
return if (!shouldRegisterOfficially) null else try {
|
||||||
val cmdmap = Bukkit.getServer().javaClass.getMethod("getCommandMap").invoke(Bukkit.getServer()) as SimpleCommandMap
|
val cmdmap =
|
||||||
|
Bukkit.getServer().javaClass.getMethod("getCommandMap").invoke(Bukkit.getServer()) as SimpleCommandMap
|
||||||
val path = command.commandPath
|
val path = command.commandPath
|
||||||
val x = path.indexOf(' ')
|
val x = path.indexOf(' ')
|
||||||
val mainPath = path.substring(0, if (x == -1) path.length else x)
|
val mainPath = path.substring(0, if (x == -1) path.length else x)
|
||||||
var bukkitCommand: Command
|
val bukkitCommand: Command
|
||||||
run {
|
//Commands conflicting with Essentials have to be registered in plugin.yml
|
||||||
//Commands conflicting with Essentials have to be registered in plugin.yml
|
val oldcmd =
|
||||||
val oldcmd = cmdmap.getCommand(command.plugin.name + ":" + mainPath) //The label with the fallback prefix is always registered
|
cmdmap.getCommand(command.plugin.name + ":" + mainPath) //The label with the fallback prefix is always registered
|
||||||
if (oldcmd == null) {
|
if (oldcmd == null) {
|
||||||
bukkitCommand = BukkitCommand(mainPath)
|
bukkitCommand = BukkitCommand(mainPath)
|
||||||
cmdmap.register(command.plugin.name, bukkitCommand)
|
cmdmap.register(command.plugin.name, bukkitCommand)
|
||||||
} else {
|
} else {
|
||||||
bukkitCommand = oldcmd
|
bukkitCommand = oldcmd
|
||||||
if (bukkitCommand is PluginCommand) (bukkitCommand as PluginCommand).executor = CommandExecutor { sender: CommandSender, command: Command, label: String, args: Array<String> -> this.executeCommand(sender, command, label, args) }
|
if (bukkitCommand is PluginCommand) bukkitCommand.setExecutor(this::executeCommand)
|
||||||
}
|
|
||||||
bukkitCommand = oldcmd ?: BukkitCommand(mainPath)
|
|
||||||
}
|
}
|
||||||
if (CommodoreProvider.isSupported()) TabcompleteHelper.registerTabcomplete(command, node, bukkitCommand)
|
if (CommodoreProvider.isSupported()) TabcompleteHelper.registerTabcomplete(command, node, bukkitCommand)
|
||||||
bukkitCommand
|
bukkitCommand
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
if (command.component == null) TBMCCoreAPI.SendException("Failed to register command in command map!", e, command.plugin) else TBMCCoreAPI.SendException("Failed to register command in command map!", e, command.component)
|
if (command.component == null)
|
||||||
|
TBMCCoreAPI.SendException("Failed to register command in command map!", e, command.plugin)
|
||||||
|
else
|
||||||
|
TBMCCoreAPI.SendException("Failed to register command in command map!", e, command.component)
|
||||||
shouldRegisterOfficially = false
|
shouldRegisterOfficially = false
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
@ -216,12 +201,14 @@ class Command2MC : Command2<ICommand2MC, Command2MCSender>('/', true), Listener
|
||||||
sender.sendMessage("§cAn internal error occurred.")
|
sender.sendMessage("§cAn internal error occurred.")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
///trim(): remove space if there are no args
|
||||||
handleCommand(Command2MCSender(sender, user.channel.get(), sender),
|
handleCommand(Command2MCSender(sender, user.channel.get(), sender),
|
||||||
("/" + command.name + " " + java.lang.String.join(" ", *args)).trim { it <= ' ' }, false) ///trim(): remove space if there are no args
|
("/${command.name} ${args.joinToString(" ")}").trim { it <= ' ' }, false
|
||||||
|
)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BukkitCommand(name: String?) : Command(name) {
|
private class BukkitCommand(name: String) : Command(name) {
|
||||||
override fun execute(sender: CommandSender, commandLabel: String, args: Array<String>): Boolean {
|
override fun execute(sender: CommandSender, commandLabel: String, args: Array<String>): Boolean {
|
||||||
return ButtonPlugin.command2MC.executeCommand(sender, this, commandLabel, args)
|
return ButtonPlugin.command2MC.executeCommand(sender, this, commandLabel, args)
|
||||||
}
|
}
|
||||||
|
@ -232,20 +219,42 @@ class Command2MC : Command2<ICommand2MC, Command2MCSender>('/', true), Listener
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IllegalArgumentException::class)
|
@Throws(IllegalArgumentException::class)
|
||||||
override fun tabComplete(sender: CommandSender, alias: String, args: Array<String>, location: Location): List<String> {
|
override fun tabComplete(
|
||||||
return emptyList()
|
sender: CommandSender,
|
||||||
|
alias: String,
|
||||||
|
args: Array<out String>?,
|
||||||
|
location: Location?
|
||||||
|
): MutableList<String> {
|
||||||
|
return mutableListOf()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private object TabcompleteHelper {
|
private object TabcompleteHelper {
|
||||||
private var commodore: Commodore? = null
|
private val commodore: Commodore by lazy {
|
||||||
private fun appendSubcommand(path: String, parent: CommandNode<Any>,
|
val commodore = CommodoreProvider.getCommodore(MainPlugin.instance) //Register all to the Core, it's easier
|
||||||
subcommand: SubcommandData<ICommand2MC>?): LiteralCommandNode<Any> {
|
commodore.register(
|
||||||
|
LiteralArgumentBuilder.literal<Any?>("un") // TODO: This is a test
|
||||||
|
.redirect(
|
||||||
|
RequiredArgumentBuilder.argument<Any?, String>(
|
||||||
|
"unsomething",
|
||||||
|
StringArgumentType.word()
|
||||||
|
).suggests { _, builder ->
|
||||||
|
builder.suggest("untest").buildFuture()
|
||||||
|
}.build()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
commodore
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun appendSubcommand(
|
||||||
|
path: String, parent: CommandNode<Any>,
|
||||||
|
subcommand: SubcommandData<ICommand2MC>?
|
||||||
|
): LiteralCommandNode<Any> {
|
||||||
var scmd: LiteralCommandNode<Any>
|
var scmd: LiteralCommandNode<Any>
|
||||||
if (parent.getChild(path) as LiteralCommandNode<kotlin.Any?>?. also { scmd = it } != null) return scmd
|
if (parent.getChild(path) as LiteralCommandNode<kotlin.Any?>?. also { scmd = it } != null) return scmd
|
||||||
val scmdBuilder = LiteralArgumentBuilder.literal<Any>(path)
|
val scmdBuilder = LiteralArgumentBuilder.literal<Any>(path)
|
||||||
if (subcommand != null) scmdBuilder.requires { o: Any? ->
|
if (subcommand != null) scmdBuilder.requires { o: Any? ->
|
||||||
val sender = commodore!!.getBukkitSender(o)
|
val sender = commodore.getBukkitSender(o)
|
||||||
subcommand.hasPermission(sender)
|
subcommand.hasPermission(sender)
|
||||||
}
|
}
|
||||||
scmd = scmdBuilder.build()
|
scmd = scmdBuilder.build()
|
||||||
|
@ -253,40 +262,33 @@ class Command2MC : Command2<ICommand2MC, Command2MCSender>('/', true), Listener
|
||||||
return scmd
|
return scmd
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun registerTabcomplete(command2MC: ICommand2MC, commandNode: LiteralCommandNode<Command2MCSender>, bukkitCommand: Command) {
|
fun registerTabcomplete(
|
||||||
if (commodore == null) {
|
command2MC: ICommand2MC,
|
||||||
commodore = CommodoreProvider.getCommodore(MainPlugin.instance) //Register all to the Core, it's easier
|
commandNode: LiteralCommandNode<Command2MCSender>,
|
||||||
commodore.register(LiteralArgumentBuilder.literal<Any?>("un")
|
bukkitCommand: Command
|
||||||
.redirect(RequiredArgumentBuilder.argument<Any?, String>(
|
) {
|
||||||
"unsomething",
|
commodore.dispatcher.root.getChild(commandNode.name) // TODO: Probably unnecessary
|
||||||
StringArgumentType.word()
|
val customTCmethods =
|
||||||
).suggests { context: CommandContext<Any?>?, builder: SuggestionsBuilder ->
|
Arrays.stream(command2MC.javaClass.declaredMethods) //val doesn't recognize the type arguments
|
||||||
builder.suggest("untest").buildFuture()
|
.flatMap { method ->
|
||||||
}.build()
|
Optional.ofNullable(method.getAnnotation(CustomTabCompleteMethod::class.java)).stream()
|
||||||
)
|
.flatMap { ctcmAnn ->
|
||||||
)
|
val paths = Optional.of(ctcmAnn.subcommand).filter { s -> s.isNotEmpty() }
|
||||||
}
|
.orElseGet {
|
||||||
commodore!!.dispatcher.root.getChild(commandNode.name) // TODO: Probably unnecessary
|
arrayOf(
|
||||||
val customTCmethods = Arrays.stream(command2MC.javaClass.declaredMethods) //val doesn't recognize the type arguments
|
CommandUtils.getCommandPath(method.name, ' ').trim { it <= ' ' })
|
||||||
.flatMap { method: Method ->
|
}
|
||||||
Optional.ofNullable(method.getAnnotation(CustomTabCompleteMethod::class.java)).stream()
|
Arrays.stream(paths).map { name: String? -> Triple(name, ctcmAnn, method) }
|
||||||
.flatMap { ctcmAnn: CustomTabCompleteMethod ->
|
}
|
||||||
val paths = Optional.of<Array<String?>>(ctcmAnn.subcommand()).filter { s: Array<String?> -> s.size > 0 }
|
}.toList()
|
||||||
.orElseGet {
|
|
||||||
arrayOf(
|
|
||||||
CommandUtils.getCommandPath(method.name, ' ').trim { it <= ' ' }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Arrays.stream(paths).map { name: String? -> Triplet(name, ctcmAnn, method) }
|
|
||||||
}
|
|
||||||
}.toList()
|
|
||||||
for (subcmd in subcmds) {
|
for (subcmd in subcmds) {
|
||||||
val subpathAsOne = CommandUtils.getCommandPath(subcmd.method.getName(), ' ').trim { it <= ' ' }
|
val subpathAsOne = CommandUtils.getCommandPath(subcmd.method.getName(), ' ').trim { it <= ' ' }
|
||||||
val subpath = subpathAsOne.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
val subpath = subpathAsOne.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||||
var scmd: CommandNode<Any> = cmd
|
var scmd: CommandNode<Any> = cmd
|
||||||
if (subpath[0].length > 0) { //If the method is def, it will contain one empty string
|
if (subpath[0].isNotEmpty()) { //If the method is def, it will contain one empty string
|
||||||
for (s in subpath) {
|
for (s in subpath) {
|
||||||
scmd = appendSubcommand(s, scmd, subcmd) //Add method name part of the path (could_be_multiple())
|
scmd =
|
||||||
|
appendSubcommand(s, scmd, subcmd) //Add method name part of the path (could_be_multiple())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val parameters: Array<Parameter> = subcmd.method.getParameters()
|
val parameters: Array<Parameter> = subcmd.method.getParameters()
|
||||||
|
@ -294,12 +296,13 @@ class Command2MC : Command2<ICommand2MC, Command2MCSender>('/', true), Listener
|
||||||
val parameter = parameters[i]
|
val parameter = parameters[i]
|
||||||
val customParamType: Boolean
|
val customParamType: Boolean
|
||||||
// TODO: Arg type
|
// TODO: Arg type
|
||||||
val param: Any = subcmd.parameters.get(i - 1)
|
val param: String = subcmd.parameters.get(i - 1)
|
||||||
val customTC = Optional.ofNullable(parameter.getAnnotation(CustomTabComplete::class.java))
|
val customTC = Optional.ofNullable(parameter.getAnnotation(CustomTabComplete::class.java))
|
||||||
.map(Function<CustomTabComplete, Array<String>> { obj: CustomTabComplete -> obj.value() })
|
.map { obj -> obj.value }
|
||||||
val customTCmethod = customTCmethods.stream().filter { t: Triplet<String?, CustomTabCompleteMethod, Method> -> subpathAsOne.equals(t.value0, ignoreCase = true) }
|
val customTCmethod =
|
||||||
.filter { t: Triplet<String?, CustomTabCompleteMethod, Method> -> param.replaceAll("[\\[\\]<>]", "").equalsIgnoreCase(t.value1.param()) }
|
customTCmethods.stream().filter { t -> subpathAsOne.equals(t.first, ignoreCase = true) }
|
||||||
.findAny()
|
.filter { t -> param.replace("[\\[\\]<>]", "").equals(t.second.param, ignoreCase = true) }
|
||||||
|
.findAny()
|
||||||
val argb: RequiredArgumentBuilder<S, T> = RequiredArgumentBuilder.argument(param, type)
|
val argb: RequiredArgumentBuilder<S, T> = RequiredArgumentBuilder.argument(param, type)
|
||||||
.suggests(SuggestionProvider<S?> { context: CommandContext<S?>, builder: SuggestionsBuilder ->
|
.suggests(SuggestionProvider<S?> { context: CommandContext<S?>, builder: SuggestionsBuilder ->
|
||||||
if (parameter.isVarArgs) { //Do it before the builder is used
|
if (parameter.isVarArgs) { //Do it before the builder is used
|
||||||
|
@ -310,8 +313,8 @@ class Command2MC : Command2<ICommand2MC, Command2MCSender>('/', true), Listener
|
||||||
var ignoreCustomParamType = false
|
var ignoreCustomParamType = false
|
||||||
if (customTCmethod.isPresent) {
|
if (customTCmethod.isPresent) {
|
||||||
val tr = customTCmethod.get()
|
val tr = customTCmethod.get()
|
||||||
if (tr.value1.ignoreTypeCompletion()) ignoreCustomParamType = true
|
if (tr.second.ignoreTypeCompletion) ignoreCustomParamType = true
|
||||||
val method = tr.value2
|
val method = tr.third
|
||||||
val params = method.parameters
|
val params = method.parameters
|
||||||
val args = arrayOfNulls<Any>(params.size)
|
val args = arrayOfNulls<Any>(params.size)
|
||||||
var j = 0
|
var j = 0
|
||||||
|
@ -319,7 +322,7 @@ class Command2MC : Command2<ICommand2MC, Command2MCSender>('/', true), Listener
|
||||||
while (j < args.size && k < subcmd.parameters.length) {
|
while (j < args.size && k < subcmd.parameters.length) {
|
||||||
val paramObj = params[j]
|
val paramObj = params[j]
|
||||||
if (CommandSender::class.java.isAssignableFrom(paramObj.type)) {
|
if (CommandSender::class.java.isAssignableFrom(paramObj.type)) {
|
||||||
args[j] = commodore!!.getBukkitSender(context.getSource())
|
args[j] = commodore.getBukkitSender(context.getSource())
|
||||||
j++
|
j++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -336,12 +339,18 @@ class Command2MC : Command2<ICommand2MC, Command2MCSender>('/', true), Listener
|
||||||
k++ //Only increment if not CommandSender
|
k++ //Only increment if not CommandSender
|
||||||
j++
|
j++
|
||||||
}
|
}
|
||||||
if (args.size == 0 || args[args.size - 1] != null) { //Arguments filled entirely
|
if (args.isEmpty() || args[args.size - 1] != null) { //Arguments filled entirely
|
||||||
try {
|
try {
|
||||||
val suggestions = method.invoke(command2MC, *args)
|
when (val suggestions = method.invoke(command2MC, *args)) {
|
||||||
if (suggestions is Iterable<*>) {
|
is Iterable<*> -> {
|
||||||
for (suggestion in suggestions) if (suggestion is String) builder.suggest(suggestion as String?) else throw ClassCastException("Bad return type! It should return an Iterable<String> or a String[].")
|
for (suggestion in suggestions) if (suggestion is String) builder.suggest(
|
||||||
} else if (suggestions is Array<String>) for (suggestion in suggestions as Array<String?>) builder.suggest(suggestion) else throw ClassCastException("Bad return type! It should return a String[] or an Iterable<String>.")
|
suggestion as String?
|
||||||
|
) else throw ClassCastException("Bad return type! It should return an Iterable<String> or a String[].")
|
||||||
|
}
|
||||||
|
|
||||||
|
is Array<*> -> for (suggestion in suggestions) builder.suggest(suggestion)
|
||||||
|
else -> throw ClassCastException("Bad return type! It should return a String[] or an Iterable<String>.")
|
||||||
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
val msg = "Failed to run tabcomplete method " + method.name + " for command " + command2MC.javaClass.simpleName
|
val msg = "Failed to run tabcomplete method " + method.name + " for command " + command2MC.javaClass.simpleName
|
||||||
if (command2MC.component == null) TBMCCoreAPI.SendException(msg, e, command2MC.plugin) else TBMCCoreAPI.SendException(msg, e, command2MC.component)
|
if (command2MC.component == null) TBMCCoreAPI.SendException(msg, e, command2MC.plugin) else TBMCCoreAPI.SendException(msg, e, command2MC.component)
|
||||||
|
@ -378,10 +387,12 @@ class Command2MC : Command2<ICommand2MC, Command2MCSender>('/', true), Listener
|
||||||
val pluginName = command2MC.plugin.name.lowercase(Locale.getDefault())
|
val pluginName = command2MC.plugin.name.lowercase(Locale.getDefault())
|
||||||
val prefixedcmd = LiteralArgumentBuilder.literal<Any>(pluginName + ":" + path.get(0))
|
val prefixedcmd = LiteralArgumentBuilder.literal<Any>(pluginName + ":" + path.get(0))
|
||||||
.redirect(maincmd).build()
|
.redirect(maincmd).build()
|
||||||
commodore!!.register(prefixedcmd)
|
commodore.register(prefixedcmd)
|
||||||
for (alias in bukkitCommand.aliases) {
|
for (alias in bukkitCommand.aliases) {
|
||||||
commodore!!.register(LiteralArgumentBuilder.literal<Any>(alias).redirect(maincmd).build())
|
commodore.register(LiteralArgumentBuilder.literal<Any>(alias).redirect(maincmd).build())
|
||||||
commodore!!.register(LiteralArgumentBuilder.literal<Any>("$pluginName:$alias").redirect(maincmd).build())
|
commodore.register(
|
||||||
|
LiteralArgumentBuilder.literal<Any>("$pluginName:$alias").redirect(maincmd).build()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -389,7 +400,7 @@ class Command2MC : Command2<ICommand2MC, Command2MCSender>('/', true), Listener
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private fun getParamConverter(cl: Class<*>, command2MC: ICommand2MC): ParamConverter<*>? {
|
private fun getParamConverter(cl: Class<*>, command2MC: ICommand2MC): ParamConverter<*>? {
|
||||||
val converter = ButtonPlugin.getCommand2MC().paramConverters[cl]
|
val converter = ButtonPlugin.command2MC.paramConverters[cl]
|
||||||
if (converter == null) {
|
if (converter == null) {
|
||||||
val msg = "Could not find a suitable converter for type " + cl.simpleName
|
val msg = "Could not find a suitable converter for type " + cl.simpleName
|
||||||
val exception: Exception = NullPointerException("converter is null")
|
val exception: Exception = NullPointerException("converter is null")
|
||||||
|
|
|
@ -14,8 +14,8 @@ class CoreCommandBuilder<S : Command2Sender, TC : ICommand2<*>, TSD : NoOpSubcom
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun build(): CoreCommandNode<S, TC, TSD> {
|
override fun build(): CoreCommandNode<S, TSD> {
|
||||||
val result = CoreCommandNode<_, TC, _>(
|
val result = CoreCommandNode<_, _>(
|
||||||
literal,
|
literal,
|
||||||
command,
|
command,
|
||||||
requirement,
|
requirement,
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
package buttondevteam.lib.chat
|
package buttondevteam.lib.chat
|
||||||
|
|
||||||
import buttondevteam.lib.chat.commands.NoOpSubcommandData
|
import buttondevteam.lib.chat.commands.NoOpSubcommandData
|
||||||
|
import buttondevteam.lib.chat.commands.SubcommandData
|
||||||
import com.mojang.brigadier.Command
|
import com.mojang.brigadier.Command
|
||||||
import com.mojang.brigadier.RedirectModifier
|
import com.mojang.brigadier.RedirectModifier
|
||||||
import com.mojang.brigadier.tree.CommandNode
|
import com.mojang.brigadier.tree.CommandNode
|
||||||
import com.mojang.brigadier.tree.LiteralCommandNode
|
import com.mojang.brigadier.tree.LiteralCommandNode
|
||||||
import java.util.function.Predicate
|
import java.util.function.Predicate
|
||||||
|
|
||||||
class CoreCommandNode<T : Command2Sender, TC : ICommand2<*>, TSD : NoOpSubcommandData>(
|
class CoreCommandNode<T : Command2Sender, TSD : NoOpSubcommandData>(
|
||||||
literal: String,
|
literal: String,
|
||||||
command: Command<T>,
|
command: Command<T>,
|
||||||
requirement: Predicate<T>,
|
requirement: Predicate<T>,
|
||||||
|
@ -15,4 +16,7 @@ class CoreCommandNode<T : Command2Sender, TC : ICommand2<*>, TSD : NoOpSubcomman
|
||||||
modifier: RedirectModifier<T>,
|
modifier: RedirectModifier<T>,
|
||||||
forks: Boolean,
|
forks: Boolean,
|
||||||
val data: TSD
|
val data: TSD
|
||||||
) : LiteralCommandNode<T>(literal, command, requirement, redirect, modifier, forks)
|
) : LiteralCommandNode<T>(literal, command, requirement, redirect, modifier, forks)
|
||||||
|
|
||||||
|
typealias CoreExecutableNode<TP, TC> = CoreCommandNode<TP, SubcommandData<TC, TP>>
|
||||||
|
typealias CoreNoOpNode<TP> = CoreCommandNode<TP, NoOpSubcommandData>
|
||||||
|
|
|
@ -13,7 +13,7 @@ import java.util.function.Function
|
||||||
*
|
*
|
||||||
* @param TP The sender's type
|
* @param TP The sender's type
|
||||||
</TP> */
|
</TP> */
|
||||||
abstract class ICommand2<TP : Command2Sender>(manager: Command2<*, TP>) {
|
abstract class ICommand2<TP : Command2Sender>(val manager: Command2<*, TP>) {
|
||||||
/**
|
/**
|
||||||
* Default handler for commands, can be used to copy the args too.
|
* Default handler for commands, can be used to copy the args too.
|
||||||
*
|
*
|
||||||
|
@ -21,7 +21,7 @@ abstract class ICommand2<TP : Command2Sender>(manager: Command2<*, TP>) {
|
||||||
* @return The success of the command
|
* @return The success of the command
|
||||||
*/
|
*/
|
||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
fun def(sender: TP): Boolean {
|
open fun def(sender: TP): Boolean {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ abstract class ICommand2<TP : Command2Sender>(manager: Command2<*, TP>) {
|
||||||
* @param message The message to send to the sender
|
* @param message The message to send to the sender
|
||||||
* @return Always true so that the usage isn't shown
|
* @return Always true so that the usage isn't shown
|
||||||
*/
|
*/
|
||||||
|
@Suppress("unused")
|
||||||
protected fun respond(sender: TP, message: String): Boolean {
|
protected fun respond(sender: TP, message: String): Boolean {
|
||||||
sender.sendMessage(message)
|
sender.sendMessage(message)
|
||||||
return true
|
return true
|
||||||
|
@ -49,23 +50,15 @@ abstract class ICommand2<TP : Command2Sender>(manager: Command2<*, TP>) {
|
||||||
return if (ann.helpText.isNotEmpty() || cc == null) ann.helpText else cc.helpText //If cc is null then it's empty array
|
return if (ann.helpText.isNotEmpty() || cc == null) ann.helpText else cc.helpText //If cc is null then it's empty array
|
||||||
}
|
}
|
||||||
|
|
||||||
private val path: String
|
/**
|
||||||
val manager: Command2<*, TP>
|
* The command's path, or name if top-level command.<br></br>
|
||||||
open val commandPath: String
|
* For example:<br></br>
|
||||||
/**
|
* "u admin updateplugin" or "u" for the top level one<br></br>
|
||||||
* The command's path, or name if top-level command.<br></br>
|
* <u>The path must be lowercase!</u><br></br>
|
||||||
* For example:<br></br>
|
*
|
||||||
* "u admin updateplugin" or "u" for the top level one<br></br>
|
* @return The command path, *which is the command class name by default* (removing any "command" from it) - Change via the [CommandClass] annotation
|
||||||
* <u>The path must be lowercase!</u><br></br>
|
*/
|
||||||
*
|
open val commandPath: String = getcmdpath()
|
||||||
* @return The command path, *which is the command class name by default* (removing any "command" from it) - Change via the [CommandClass] annotation
|
|
||||||
*/
|
|
||||||
get() = path
|
|
||||||
|
|
||||||
init {
|
|
||||||
path = getcmdpath()
|
|
||||||
this.manager = manager
|
|
||||||
}
|
|
||||||
|
|
||||||
open val commandPaths: Array<String>
|
open val commandPaths: Array<String>
|
||||||
/**
|
/**
|
||||||
|
@ -74,8 +67,7 @@ abstract class ICommand2<TP : Command2Sender>(manager: Command2<*, TP>) {
|
||||||
*
|
*
|
||||||
* @return The full command paths that this command should be registered under in addition to the default one.
|
* @return The full command paths that this command should be registered under in addition to the default one.
|
||||||
*/
|
*/
|
||||||
get() =// TODO: Deal with this (used for channel IDs)
|
get() = EMPTY_PATHS // TODO: Deal with this (used for channel IDs)
|
||||||
EMPTY_PATHS
|
|
||||||
|
|
||||||
private fun getcmdpath(): String {
|
private fun getcmdpath(): String {
|
||||||
if (!javaClass.isAnnotationPresent(CommandClass::class.java)) throw RuntimeException(
|
if (!javaClass.isAnnotationPresent(CommandClass::class.java)) throw RuntimeException(
|
||||||
|
|
|
@ -7,14 +7,14 @@ import buttondevteam.lib.architecture.Component
|
||||||
abstract class ICommand2MC : ICommand2<Command2MCSender>(command2MC) {
|
abstract class ICommand2MC : ICommand2<Command2MCSender>(command2MC) {
|
||||||
private var _plugin: ButtonPlugin? = null
|
private var _plugin: ButtonPlugin? = null
|
||||||
var plugin: ButtonPlugin
|
var plugin: ButtonPlugin
|
||||||
get() = _plugin ?: throw IllegalStateException("The command is not registered to a plugin!")
|
get() = _plugin ?: throw IllegalStateException("The command is not registered to a Button plugin!")
|
||||||
private set(value) {
|
private set(value) {
|
||||||
if (_plugin != null) throw IllegalStateException("The command is already assigned to a plugin!")
|
if (_plugin != null) throw IllegalStateException("The command is already assigned to a Button plugin!")
|
||||||
_plugin = value
|
_plugin = value
|
||||||
}
|
}
|
||||||
private var _component: Component<*>? = null
|
private var _component: Component<*>? = null
|
||||||
var component: Component<*>
|
var component: Component<*>?
|
||||||
get() = _component ?: throw IllegalStateException("The command is not registered to a component!")
|
get() = _component
|
||||||
private set(value) {
|
private set(value) {
|
||||||
if (_component != null) throw IllegalStateException("The command is already assigned to a component!")
|
if (_component != null) throw IllegalStateException("The command is already assigned to a component!")
|
||||||
_component = value
|
_component = value
|
||||||
|
|
|
@ -2,8 +2,8 @@ package buttondevteam.lib.chat.commands
|
||||||
|
|
||||||
import buttondevteam.lib.chat.Command2Sender
|
import buttondevteam.lib.chat.Command2Sender
|
||||||
import buttondevteam.lib.chat.CoreCommandNode
|
import buttondevteam.lib.chat.CoreCommandNode
|
||||||
|
import buttondevteam.lib.chat.CoreExecutableNode
|
||||||
import buttondevteam.lib.chat.ICommand2
|
import buttondevteam.lib.chat.ICommand2
|
||||||
import com.mojang.brigadier.context.CommandContext
|
|
||||||
import com.mojang.brigadier.tree.CommandNode
|
import com.mojang.brigadier.tree.CommandNode
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
@ -24,20 +24,15 @@ object CommandUtils {
|
||||||
* Casts the node to whatever you say. Use responsibly.
|
* Casts the node to whatever you say. Use responsibly.
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun <TP : Command2Sender, TC : ICommand2<*>, TSD : NoOpSubcommandData> CommandNode<TP>.core(): CoreCommandNode<TP, TC, TSD> {
|
fun <TP : Command2Sender, TSD : NoOpSubcommandData> CommandNode<TP>.core(): CoreCommandNode<TP, TSD> {
|
||||||
return this as CoreCommandNode<TP, TC, TSD>
|
return this as CoreCommandNode<TP, TSD>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the node as an executable core command node or returns null if it's a no-op node.
|
* Returns the node as an executable core command node or returns null if it's a no-op node.
|
||||||
*/
|
*/
|
||||||
fun <TP : Command2Sender, TC : ICommand2<*>> CommandNode<TP>.coreExecutable(): CoreCommandNode<TP, TC, SubcommandData<TC, TP>>? {
|
fun <TP : Command2Sender, TC : ICommand2<*>> CommandNode<TP>.coreExecutable(): CoreExecutableNode<TP, TC>? {
|
||||||
val ret = core<TP, TC, NoOpSubcommandData>()
|
val ret = core<TP, NoOpSubcommandData>()
|
||||||
return if (ret.data is SubcommandData<*, *>) ret.core() else null
|
return if (ret.data is SubcommandData<*, *>) ret.core() else null
|
||||||
}
|
}
|
||||||
|
|
||||||
val <TP : Command2Sender> CommandContext<TP>.subcommandPath
|
|
||||||
get(): String {
|
|
||||||
TODO("Return command path")
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -47,7 +47,7 @@ class SubcommandData<TC : ICommand2<*>, TP : Command2Sender>(
|
||||||
*/
|
*/
|
||||||
val annotations: Array<Annotation>,
|
val annotations: Array<Annotation>,
|
||||||
/**
|
/**
|
||||||
* The full command path of this subcommand.
|
* The space-separated full command path of this subcommand.
|
||||||
*/
|
*/
|
||||||
val fullPath: String
|
val fullPath: String
|
||||||
) : NoOpSubcommandData(helpTextGetter) {
|
) : NoOpSubcommandData(helpTextGetter) {
|
||||||
|
|
Loading…
Reference in a new issue