Convert some more code to Kotlin
Basically done with converting Command2 Also moved the Minecraft part of the param converter to Command2MC, although the user object getter should be made more generic
This commit is contained in:
parent
0bf1f9789b
commit
a5099a65d1
10 changed files with 132 additions and 124 deletions
|
@ -72,7 +72,6 @@
|
|||
<artifactSet>
|
||||
<includes>
|
||||
<include>me.lucko:commodore</include>
|
||||
<include>org.javatuples:javatuples</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
<relocations>
|
||||
|
@ -226,11 +225,6 @@
|
|||
<version>1.11</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.javatuples</groupId>
|
||||
<artifactId>javatuples</artifactId>
|
||||
<version>1.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
|
|
|
@ -106,7 +106,7 @@ public class MainPlugin extends ButtonPlugin {
|
|||
registerCommand(new ComponentCommand());
|
||||
registerCommand(new ChromaCommand());
|
||||
TBMCCoreAPI.RegisterEventsForExceptions(new PlayerListener(), this);
|
||||
TBMCCoreAPI.RegisterEventsForExceptions(getCommand2MC(), this);
|
||||
TBMCCoreAPI.RegisterEventsForExceptions(Companion.getCommand2MC(), this);
|
||||
ChromaGamerBase.addConverter(commandSender -> Optional.ofNullable(commandSender instanceof ConsoleCommandSender || commandSender instanceof BlockCommandSender
|
||||
? TBMCPlayer.getPlayer(new UUID(0, 0), TBMCPlayer.class) : null)); //Console & cmdblocks
|
||||
ChromaGamerBase.addConverter(sender -> Optional.ofNullable(sender instanceof Player
|
||||
|
@ -125,8 +125,8 @@ public class MainPlugin extends ButtonPlugin {
|
|||
TBMCChatAPI.RegisterChatChannel(new ChatRoom("§bBLUE§f", Color.Blue, "blue"));
|
||||
TBMCChatAPI.RegisterChatChannel(new ChatRoom("§5PURPLE§f", Color.DarkPurple, "purple"));
|
||||
Supplier<Iterable<String>> playerSupplier = () -> Bukkit.getOnlinePlayers().stream().map(HumanEntity::getName)::iterator;
|
||||
getCommand2MC().addParamConverter(OfflinePlayer.class, Bukkit::getOfflinePlayer, "Player not found!", playerSupplier);
|
||||
getCommand2MC().addParamConverter(Player.class, Bukkit::getPlayer, "Online player not found!", playerSupplier);
|
||||
Companion.getCommand2MC().addParamConverter(OfflinePlayer.class, Bukkit::getOfflinePlayer, "Player not found!", playerSupplier);
|
||||
Companion.getCommand2MC().addParamConverter(Player.class, Bukkit::getPlayer, "Online player not found!", playerSupplier);
|
||||
if (writePluginList.get()) {
|
||||
try {
|
||||
Files.write(new File("plugins", "plugins.txt").toPath(), Arrays.stream(Bukkit.getPluginManager().getPlugins()).map(p -> (CharSequence) p.getDataFolder().getName())::iterator);
|
||||
|
|
|
@ -5,8 +5,6 @@ import buttondevteam.core.ComponentManager
|
|||
import buttondevteam.lib.TBMCCoreAPI
|
||||
import buttondevteam.lib.architecture.Component.Companion.updateConfig
|
||||
import buttondevteam.lib.chat.Command2MC
|
||||
import buttondevteam.lib.chat.Command2MC.registerCommand
|
||||
import buttondevteam.lib.chat.Command2MC.unregisterCommands
|
||||
import buttondevteam.lib.chat.ICommand2MC
|
||||
import lombok.AccessLevel
|
||||
import lombok.Getter
|
||||
|
@ -22,8 +20,7 @@ import java.util.function.Function
|
|||
|
||||
@HasConfig(global = true)
|
||||
abstract class ButtonPlugin : JavaPlugin() {
|
||||
@Getter(AccessLevel.PROTECTED)
|
||||
private val iConfig = IHaveConfig { saveConfig() }
|
||||
protected val iConfig = IHaveConfig { saveConfig() }
|
||||
private var yaml: CommentedConfiguration? = null
|
||||
|
||||
@Getter(AccessLevel.PROTECTED)
|
||||
|
@ -74,7 +71,7 @@ abstract class ButtonPlugin : JavaPlugin() {
|
|||
ComponentManager.unregComponents(this)
|
||||
pluginDisable()
|
||||
if (ConfigData.saveNow(config)) logger.info("Saved configuration changes.")
|
||||
ButtonPlugin.getCommand2MC().unregisterCommands(this)
|
||||
command2MC.unregisterCommands(this)
|
||||
} catch (e: Exception) {
|
||||
TBMCCoreAPI.SendException("Error while disabling plugin $name!", e, this)
|
||||
}
|
||||
|
@ -122,7 +119,7 @@ abstract class ButtonPlugin : JavaPlugin() {
|
|||
|
||||
override fun getConfig(): FileConfiguration {
|
||||
if (yaml == null) justReload()
|
||||
return if (yaml == null) YamlConfiguration() else yaml //Return a temporary instance
|
||||
return yaml ?: YamlConfiguration() //Return a temporary instance
|
||||
}
|
||||
|
||||
override fun saveConfig() {
|
||||
|
@ -140,16 +137,15 @@ abstract class ButtonPlugin : JavaPlugin() {
|
|||
*/
|
||||
fun registerCommand(command: ICommand2MC) {
|
||||
command.registerToPlugin(this)
|
||||
ButtonPlugin.getCommand2MC().registerCommand(command)
|
||||
command2MC.registerCommand(command)
|
||||
}
|
||||
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS)
|
||||
annotation class ConfigOpts(val disableConfigGen: Boolean = false)
|
||||
companion object {
|
||||
@Getter //Needs to be static as we don't know the plugin when a command is handled
|
||||
|
||||
private val command2MC = Command2MC()
|
||||
//Needs to be static as we don't know the plugin when a command is handled
|
||||
val command2MC = Command2MC()
|
||||
fun configGenAllowed(obj: Any): Boolean {
|
||||
return !Optional.ofNullable(obj.javaClass.getAnnotation(ConfigOpts::class.java))
|
||||
.map(Function<ConfigOpts, Boolean> { obj: ConfigOpts -> obj.disableConfigGen() }).orElse(false)
|
||||
|
|
|
@ -2,9 +2,8 @@ package buttondevteam.lib.chat
|
|||
|
||||
import buttondevteam.core.MainPlugin
|
||||
import buttondevteam.lib.TBMCCoreAPI
|
||||
import buttondevteam.lib.chat.Command2.Subcommand
|
||||
import buttondevteam.lib.chat.commands.*
|
||||
import buttondevteam.lib.player.ChromaGamerBase
|
||||
import buttondevteam.lib.chat.commands.CommandUtils.core
|
||||
import com.mojang.brigadier.CommandDispatcher
|
||||
import com.mojang.brigadier.arguments.*
|
||||
import com.mojang.brigadier.builder.ArgumentBuilder
|
||||
|
@ -15,8 +14,6 @@ import com.mojang.brigadier.tree.CommandNode
|
|||
import com.mojang.brigadier.tree.LiteralCommandNode
|
||||
import lombok.RequiredArgsConstructor
|
||||
import org.bukkit.Bukkit
|
||||
import org.javatuples.Pair
|
||||
import org.javatuples.Triplet
|
||||
import java.lang.reflect.Method
|
||||
import java.util.function.Function
|
||||
import java.util.function.Predicate
|
||||
|
@ -90,7 +87,7 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender> {
|
|||
</T> */
|
||||
open fun <T> addParamConverter(cl: Class<T>, converter: Function<String, T>, errormsg: String,
|
||||
allSupplier: Supplier<Iterable<String>>) {
|
||||
paramConverters[cl] = ParamConverter<T>(converter, errormsg, allSupplier)
|
||||
paramConverters[cl] = ParamConverter(converter, errormsg, allSupplier)
|
||||
}
|
||||
|
||||
open fun handleCommand(sender: TP, commandline: String): Boolean {
|
||||
|
@ -112,22 +109,10 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender> {
|
|||
}
|
||||
|
||||
//TODO: Add to the help
|
||||
private fun processSenderType(sender: TP, sd: SubcommandData<TC, TP>, params: ArrayList<Any>): Boolean {
|
||||
val sendertype = sd.senderType
|
||||
val cg: ChromaGamerBase
|
||||
if (sendertype.isAssignableFrom(sender.javaClass)) params.add(sender) //The command either expects a CommandSender or it is a Player, or some other expected type
|
||||
else if (sender is Command2MCSender // TODO: This is Minecraft only
|
||||
&& sendertype.isAssignableFrom((sender as Command2MCSender).sender.javaClass))
|
||||
params.add((sender as Command2MCSender).sender)
|
||||
else if ((ChromaGamerBase::class.java.isAssignableFrom(sendertype) && sender is Command2MCSender)
|
||||
&& ChromaGamerBase.getFromSender((sender as Command2MCSender).sender).also { cg = it } != null && cg.javaClass == sendertype) //The command expects a user of our system
|
||||
params.add(cg) else {
|
||||
val type = sendertype.simpleName.fold("") { s, ch -> s + if (ch.isUpperCase()) " " + ch.lowercase() else ch }
|
||||
sender.sendMessage("§cYou 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
|
||||
return true
|
||||
}
|
||||
return false
|
||||
open fun convertSenderType(sender: TP, senderType: Class<*>): Any? {
|
||||
//The command either expects a CommandSender or it is a Player, or some other expected type
|
||||
if (senderType.isAssignableFrom(sender.javaClass)) return sender
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -146,17 +131,18 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender> {
|
|||
*/
|
||||
protected fun registerCommandSuper(command: TC): LiteralCommandNode<TP> {
|
||||
var mainCommandNode: LiteralCommandNode<TP>? = null
|
||||
for (meth in command.javaClass.getMethods()) {
|
||||
val ann = meth.getAnnotation<Subcommand>(Subcommand::class.java) ?: continue
|
||||
for (meth in command.javaClass.methods) {
|
||||
val ann = meth.getAnnotation(Subcommand::class.java) ?: continue
|
||||
val methodPath = CommandUtils.getCommandPath(meth.name, ' ')
|
||||
val result = registerNodeFromPath(command!!.commandPath + methodPath)
|
||||
result.value0.addChild(getExecutableNode(meth, command, ann, result.value2, CommandArgumentHelpManager(command)))
|
||||
if (mainCommandNode == null) mainCommandNode = result.value1 else if (result.value1!!.name != mainCommandNode.name) {
|
||||
val (lastNode, mainNode, remainingPath) = registerNodeFromPath(command.commandPath + methodPath)
|
||||
lastNode.addChild(getExecutableNode(meth, command, ann, remainingPath, CommandArgumentHelpManager(command)))
|
||||
if (mainCommandNode == null) mainCommandNode = mainNode
|
||||
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)
|
||||
}
|
||||
}
|
||||
if (mainCommandNode == null) {
|
||||
throw RuntimeException("There are no subcommands defined in the command class " + command.javaClass.getSimpleName() + "!")
|
||||
throw RuntimeException("There are no subcommands defined in the command class " + command.javaClass.simpleName + "!")
|
||||
}
|
||||
return mainCommandNode
|
||||
}
|
||||
|
@ -170,18 +156,18 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender> {
|
|||
* @return The executable node
|
||||
*/
|
||||
private fun getExecutableNode(method: Method, command: TC, ann: Subcommand, path: String, argHelpManager: CommandArgumentHelpManager<TC, TP>): LiteralCommandNode<TP> {
|
||||
val paramsAndSenderType = getCommandParametersAndSender(method, argHelpManager) // Param order is important
|
||||
val params = paramsAndSenderType.value0
|
||||
val (params, _) = getCommandParametersAndSender(method, argHelpManager) // Param order is important
|
||||
val paramMap = HashMap<String, CommandArgument?>()
|
||||
for (param in params) {
|
||||
paramMap[param!!.name] = param
|
||||
paramMap[param.name] = param
|
||||
}
|
||||
val node = CoreCommandBuilder.literal<TP, TC>(path, params[0]!!.type, paramMap, params, command)
|
||||
.helps(command!!.getHelpText(method, ann)).permits { sender: TP -> hasPermission(sender, command, method) }
|
||||
val node = CoreCommandBuilder.literal<TP, TC>(path, params[0].type, paramMap, params, command)
|
||||
.helps(command.getHelpText(method, ann)).permits { sender: TP -> hasPermission(sender, command, method) }
|
||||
.executes { context: CommandContext<TP> -> executeCommand(context) }
|
||||
var parent: ArgumentBuilder<TP, *> = node
|
||||
for (param in params) { // Register parameters in the right order
|
||||
parent.then(CoreArgumentBuilder.argument(param!!.name, getArgumentType(param), param.optional).also { parent = it })
|
||||
val argType = getArgumentType(param)
|
||||
parent.then(CoreArgumentBuilder.argument<TP, _>(param.name, argType, param.optional).also { parent = it })
|
||||
}
|
||||
return node.build()
|
||||
}
|
||||
|
@ -193,7 +179,7 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender> {
|
|||
* @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)
|
||||
*/
|
||||
private fun registerNodeFromPath(path: String): Triplet<CommandNode<TP>, LiteralCommandNode<TP>?, String> {
|
||||
private fun registerNodeFromPath(path: String): Triple<CommandNode<TP>, LiteralCommandNode<TP>?, String> {
|
||||
val split = path.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
var parent: CommandNode<TP> = dispatcher.root
|
||||
var mainCommand: LiteralCommandNode<TP>? = null
|
||||
|
@ -203,7 +189,7 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender> {
|
|||
if (child == null) parent.addChild(CoreCommandBuilder.literalNoOp<TP, TC>(part).executes { context: CommandContext<TP> -> executeHelpText(context) }.build().also { parent = it }) else parent = child
|
||||
if (i == 0) mainCommand = parent as LiteralCommandNode<TP> // Has to be a literal, if not, well, error
|
||||
}
|
||||
return Triplet(parent, mainCommand, split[split.size - 1])
|
||||
return Triple(parent, mainCommand, split[split.size - 1])
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -214,21 +200,20 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender> {
|
|||
* @return Parameter data objects and the sender type
|
||||
* @throws RuntimeException If there is no sender parameter declared in the method
|
||||
*/
|
||||
private fun getCommandParametersAndSender(method: Method, argHelpManager: CommandArgumentHelpManager<TC, TP>): Pair<Array<CommandArgument?>, Class<*>> {
|
||||
private fun getCommandParametersAndSender(method: Method, argHelpManager: CommandArgumentHelpManager<TC, TP>): Pair<List<CommandArgument>, Class<*>> {
|
||||
val parameters = method.parameters
|
||||
if (parameters.size == 0) throw RuntimeException("No sender parameter for method '$method'")
|
||||
val ret = arrayOfNulls<CommandArgument>(parameters.size)
|
||||
if (parameters.isEmpty()) throw RuntimeException("No sender parameter for method '$method'")
|
||||
val usage = argHelpManager.getParameterHelpForMethod(method)
|
||||
val paramNames = usage?.split(" ".toRegex())?.dropLastWhile { it.isEmpty() }?.toTypedArray()
|
||||
for (i in 1 until parameters.size) {
|
||||
val numAnn = parameters[i].getAnnotation(NumberArg::class.java)
|
||||
ret[i - 1] = CommandArgument(paramNames?.get(i) ?: "param$i", parameters[i].type,
|
||||
parameters[i].isVarArgs || parameters[i].isAnnotationPresent(TextArg::class.java),
|
||||
if (numAnn == null) null else Pair(numAnn.lowerLimit(), numAnn.upperLimit()),
|
||||
parameters[i].isAnnotationPresent(OptionalArg::class.java),
|
||||
paramNames?.get(i) ?: "param$i") // TODO: Description (JavaDoc?)
|
||||
}
|
||||
return Pair(ret, parameters[0].type)
|
||||
val paramNames = usage?.split(" ")
|
||||
return Pair(parameters.zip(paramNames ?: (1 until parameters.size).map { i -> "param$i" })
|
||||
.map { (param, name) ->
|
||||
val numAnn = param.getAnnotation(NumberArg::class.java)
|
||||
CommandArgument(name, param.type,
|
||||
param.isVarArgs || param.isAnnotationPresent(TextArg::class.java),
|
||||
if (numAnn == null) Pair(Double.MIN_VALUE, Double.MAX_VALUE) else Pair(numAnn.lowerLimit, numAnn.upperLimit),
|
||||
param.isAnnotationPresent(OptionalArg::class.java),
|
||||
name)
|
||||
}, parameters[0].type)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -238,13 +223,24 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender> {
|
|||
* @param arg Our representation of the command argument
|
||||
* @return The Brigadier representation of the command argument
|
||||
*/
|
||||
private fun getArgumentType(arg: CommandArgument?): ArgumentType<*> {
|
||||
private fun getArgumentType(arg: CommandArgument?): ArgumentType<out Any> {
|
||||
val ptype = arg!!.type
|
||||
val lowerLimit: Number = arg.limits.value0
|
||||
val upperLimit: Number = arg.limits.value1
|
||||
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) IntegerArgumentType.integer(lowerLimit.toInt(), upperLimit.toInt()) else if (ptype == Long::class.javaPrimitiveType || ptype == Long::class.java) LongArgumentType.longArg(lowerLimit.toLong(), upperLimit.toLong()) else if (ptype == Float::class.javaPrimitiveType || ptype == Float::class.java) FloatArgumentType.floatArg(lowerLimit.toFloat(), upperLimit.toFloat()) else if (ptype == Double::class.javaPrimitiveType || ptype == Double::class.java) DoubleArgumentType.doubleArg(lowerLimit.toDouble(), upperLimit.toDouble()) 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 {
|
||||
StringArgumentType.word()
|
||||
}
|
||||
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)
|
||||
IntegerArgumentType.integer(lowerLimit.toInt(), upperLimit.toInt())
|
||||
else if (ptype == Long::class.javaPrimitiveType || ptype == Long::class.java)
|
||||
LongArgumentType.longArg(lowerLimit.toLong(), upperLimit.toLong())
|
||||
else if (ptype == Float::class.javaPrimitiveType || ptype == Float::class.java)
|
||||
FloatArgumentType.floatArg(lowerLimit.toFloat(), upperLimit.toFloat())
|
||||
else if (ptype == Double::class.javaPrimitiveType || ptype == Double::class.java)
|
||||
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 StringArgumentType.word()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -277,6 +273,11 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender> {
|
|||
return;
|
||||
}
|
||||
// TODO: WIP
|
||||
|
||||
val type = sendertype.simpleName.fold("") { s, ch -> s + if (ch.isUpperCase()) " " + ch.lowercase() else ch }
|
||||
sender.sendMessage("§cYou 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
|
||||
|
||||
if (processSenderType(sender, sd, params, parameterTypes)) return; // Checks if the sender is the wrong type
|
||||
val args = parsed.getContext().getArguments();
|
||||
for (var arg : sd.arguments.entrySet()) {*/
|
||||
|
@ -325,16 +326,15 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender> {
|
|||
}
|
||||
|
||||
abstract fun hasPermission(sender: TP, command: TC, subcommand: Method?): Boolean
|
||||
val commandsText: Array<String>
|
||||
get() = commandHelp.toTypedArray()
|
||||
val commandsText: Array<String> get() = commandHelp.toTypedArray()
|
||||
|
||||
/**
|
||||
* Get all registered command nodes. This returns all registered Chroma commands with all the information about them.
|
||||
*
|
||||
* @return A set of command node objects containing the commands
|
||||
*/
|
||||
val commandNodes: Set<CoreCommandNode<TP, TC?>?>
|
||||
get() = dispatcher.root.children.stream().map { node: CommandNode<TP>? -> node as CoreCommandNode<TP, TC?>? }.collect(Collectors.toUnmodifiableSet())
|
||||
val commandNodes: Set<CoreCommandNode<TP, TC>>
|
||||
get() = dispatcher.root.children.stream().map { node: CommandNode<TP> -> node.core<TP, TC>() }.collect(Collectors.toUnmodifiableSet())
|
||||
|
||||
/**
|
||||
* Get a node that belongs to the given command.
|
||||
|
@ -343,7 +343,7 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender> {
|
|||
* @return A command node
|
||||
*/
|
||||
fun getCommandNode(command: String?): CoreCommandNode<TP, TC> {
|
||||
return dispatcher.root.getChild(command) as CoreCommandNode<TP, TC>
|
||||
return dispatcher.root.getChild(command).core()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -352,7 +352,7 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender> {
|
|||
* @param command The command class (object) to unregister
|
||||
*/
|
||||
fun unregisterCommand(command: ICommand2<TP>) {
|
||||
dispatcher.root.children.removeIf { node: CommandNode<TP> -> (node as CoreCommandNode<TP, TC>).data.command === command }
|
||||
dispatcher.root.children.removeIf { node: CommandNode<TP> -> node.core<TP, TC>().data.command === command }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -360,14 +360,14 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender> {
|
|||
*
|
||||
* @param condition The condition for removing a given command
|
||||
*/
|
||||
fun unregisterCommandIf(condition: Predicate<CoreCommandNode<TP, TC>?>, nested: Boolean) {
|
||||
dispatcher.root.children.removeIf { node: CommandNode<TP>? -> condition.test(node as CoreCommandNode<TP, TC>?) }
|
||||
if (nested) for (child in dispatcher.root.children) unregisterCommandIf(condition, child as CoreCommandNode<TP, TC>)
|
||||
fun unregisterCommandIf(condition: Predicate<CoreCommandNode<TP, TC>>, nested: Boolean) {
|
||||
dispatcher.root.children.removeIf { node: CommandNode<TP> -> condition.test(node.core()) }
|
||||
if (nested) for (child in dispatcher.root.children) unregisterCommandIf(condition, child.core())
|
||||
}
|
||||
|
||||
private fun unregisterCommandIf(condition: Predicate<CoreCommandNode<TP, TC>?>, root: CoreCommandNode<TP, TC>) {
|
||||
private fun unregisterCommandIf(condition: Predicate<CoreCommandNode<TP, TC>>, root: CoreCommandNode<TP, TC>) {
|
||||
// Can't use getCoreChildren() here because the collection needs to be modifiable
|
||||
root.children.removeIf { node: CommandNode<TP>? -> condition.test(node as CoreCommandNode<TP, TC>?) }
|
||||
root.children.removeIf { node: CommandNode<TP> -> condition.test(node.core()) }
|
||||
for (child in root.coreChildren) unregisterCommandIf(condition, child)
|
||||
}
|
||||
}
|
|
@ -28,7 +28,6 @@ import org.bukkit.entity.Player
|
|||
import org.bukkit.event.Listener
|
||||
import org.bukkit.permissions.Permission
|
||||
import org.bukkit.permissions.PermissionDefault
|
||||
import org.javatuples.Triplet
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Parameter
|
||||
import java.util.*
|
||||
|
@ -36,7 +35,7 @@ import java.util.function.BiConsumer
|
|||
import java.util.function.Function
|
||||
import java.util.function.Supplier
|
||||
|
||||
class Command2MC : Command2<ICommand2MC?, Command2MCSender?>('/', true), Listener {
|
||||
class Command2MC : Command2<ICommand2MC, Command2MCSender>('/', true), Listener {
|
||||
/**
|
||||
* Don't use directly, use the method in Component and ButtonPlugin to automatically unregister the command when needed.
|
||||
*
|
||||
|
@ -149,8 +148,25 @@ class Command2MC : Command2<ICommand2MC?, Command2MCSender?>('/', true), Listene
|
|||
super.addParamConverter(cl, converter, "§c$errormsg", allSupplier)
|
||||
}
|
||||
|
||||
override fun convertSenderType(sender: Command2MCSender, senderType: Class<*>): Any? {
|
||||
val original = super.convertSenderType(sender, senderType)
|
||||
if (original != null) {
|
||||
return original
|
||||
}
|
||||
// Check Bukkit sender type
|
||||
if (senderType.isAssignableFrom(sender.sender.javaClass))
|
||||
return sender.sender
|
||||
//The command expects a user of our system
|
||||
if (ChromaGamerBase::class.java.isAssignableFrom(senderType)) {
|
||||
val cg = ChromaGamerBase.getFromSender(sender.sender)
|
||||
if (cg?.javaClass == senderType)
|
||||
return cg
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun unregisterCommands(plugin: ButtonPlugin) {
|
||||
unregisterCommandIf({ node: CoreCommandNode<Command2MCSender?, ICommand2MC?> -> Optional.ofNullable(node.data.command).map { obj: ICommand2MC -> obj.plugin }.map { obj: ButtonPlugin? -> plugin.equals(obj) }.orElse(false) }, true)
|
||||
unregisterCommandIf({ node -> Optional.ofNullable(node.data.command).map { obj -> obj.plugin }.map { obj -> plugin == obj }.orElse(false) }, true)
|
||||
}
|
||||
|
||||
fun unregisterCommands(component: Component<*>) {
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
package buttondevteam.lib.chat.commands;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.javatuples.Pair;
|
||||
|
||||
/**
|
||||
* A command argument's information to be used to construct the command.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class CommandArgument {
|
||||
public final String name;
|
||||
public final Class<?> type;
|
||||
public final boolean greedy;
|
||||
public final Pair<Double, Double> limits;
|
||||
public final boolean optional;
|
||||
public final String description;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package buttondevteam.lib.chat.commands
|
||||
|
||||
/**
|
||||
* A command argument's information to be used to construct the command.
|
||||
*/
|
||||
class CommandArgument(
|
||||
val name: String,
|
||||
val type: Class<*>,
|
||||
val greedy: Boolean,
|
||||
val limits: Pair<Double, Double>,
|
||||
val optional: Boolean,
|
||||
val description: String
|
||||
)
|
|
@ -1,19 +0,0 @@
|
|||
package buttondevteam.lib.chat.commands;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@UtilityClass
|
||||
public class CommandUtils {
|
||||
/**
|
||||
* Returns the path of the given subcommand excluding the class' path. It will start with the given replace char.
|
||||
*
|
||||
* @param methodName The method's name, method.getName()
|
||||
* @param replaceChar The character to use between subcommands
|
||||
* @return The command path starting with the replacement char.
|
||||
*/
|
||||
@NotNull
|
||||
public static String getCommandPath(String methodName, char replaceChar) {
|
||||
return methodName.equals("def") ? "" : replaceChar + methodName.replace('_', replaceChar).toLowerCase();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package buttondevteam.lib.chat.commands
|
||||
|
||||
import buttondevteam.lib.chat.Command2Sender
|
||||
import buttondevteam.lib.chat.CoreCommandNode
|
||||
import buttondevteam.lib.chat.ICommand2
|
||||
import com.mojang.brigadier.tree.CommandNode
|
||||
import java.util.*
|
||||
|
||||
object CommandUtils {
|
||||
/**
|
||||
* Returns the path of the given subcommand excluding the class' path. It will start with the given replace char.
|
||||
*
|
||||
* @param methodName The method's name, method.getName()
|
||||
* @param replaceChar The character to use between subcommands
|
||||
* @return The command path starting with the replacement char.
|
||||
*/
|
||||
fun getCommandPath(methodName: String, replaceChar: Char): String {
|
||||
return if (methodName == "def") "" else replaceChar.toString() + methodName.replace('_', replaceChar).lowercase(Locale.getDefault())
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <TP : Command2Sender, TC : ICommand2<*>> CommandNode<TP>.core(): CoreCommandNode<TP, TC> {
|
||||
return this as CoreCommandNode<TP, TC>
|
||||
}
|
||||
}
|
|
@ -153,7 +153,7 @@ public abstract class ChromaGamerBase {
|
|||
* @param sender The sender to use
|
||||
* @return A user as returned by a converter or null if none can supply it
|
||||
*/
|
||||
public static ChromaGamerBase getFromSender(CommandSender sender) {
|
||||
public static ChromaGamerBase getFromSender(CommandSender sender) { // TODO: Use Command2Sender
|
||||
for (val converter : senderConverters) {
|
||||
val ocg = converter.apply(sender);
|
||||
if (ocg.isPresent())
|
||||
|
|
Loading…
Reference in a new issue