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>
|
<artifactSet>
|
||||||
<includes>
|
<includes>
|
||||||
<include>me.lucko:commodore</include>
|
<include>me.lucko:commodore</include>
|
||||||
<include>org.javatuples:javatuples</include>
|
|
||||||
</includes>
|
</includes>
|
||||||
</artifactSet>
|
</artifactSet>
|
||||||
<relocations>
|
<relocations>
|
||||||
|
@ -226,11 +225,6 @@
|
||||||
<version>1.11</version>
|
<version>1.11</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.javatuples</groupId>
|
|
||||||
<artifactId>javatuples</artifactId>
|
|
||||||
<version>1.2</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jetbrains.kotlin</groupId>
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
<artifactId>kotlin-stdlib</artifactId>
|
<artifactId>kotlin-stdlib</artifactId>
|
||||||
|
|
|
@ -106,7 +106,7 @@ public class MainPlugin extends ButtonPlugin {
|
||||||
registerCommand(new ComponentCommand());
|
registerCommand(new ComponentCommand());
|
||||||
registerCommand(new ChromaCommand());
|
registerCommand(new ChromaCommand());
|
||||||
TBMCCoreAPI.RegisterEventsForExceptions(new PlayerListener(), this);
|
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
|
ChromaGamerBase.addConverter(commandSender -> Optional.ofNullable(commandSender instanceof ConsoleCommandSender || commandSender instanceof BlockCommandSender
|
||||||
? TBMCPlayer.getPlayer(new UUID(0, 0), TBMCPlayer.class) : null)); //Console & cmdblocks
|
? TBMCPlayer.getPlayer(new UUID(0, 0), TBMCPlayer.class) : null)); //Console & cmdblocks
|
||||||
ChromaGamerBase.addConverter(sender -> Optional.ofNullable(sender instanceof Player
|
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("§bBLUE§f", Color.Blue, "blue"));
|
||||||
TBMCChatAPI.RegisterChatChannel(new ChatRoom("§5PURPLE§f", Color.DarkPurple, "purple"));
|
TBMCChatAPI.RegisterChatChannel(new ChatRoom("§5PURPLE§f", Color.DarkPurple, "purple"));
|
||||||
Supplier<Iterable<String>> playerSupplier = () -> Bukkit.getOnlinePlayers().stream().map(HumanEntity::getName)::iterator;
|
Supplier<Iterable<String>> playerSupplier = () -> Bukkit.getOnlinePlayers().stream().map(HumanEntity::getName)::iterator;
|
||||||
getCommand2MC().addParamConverter(OfflinePlayer.class, Bukkit::getOfflinePlayer, "Player not found!", playerSupplier);
|
Companion.getCommand2MC().addParamConverter(OfflinePlayer.class, Bukkit::getOfflinePlayer, "Player not found!", playerSupplier);
|
||||||
getCommand2MC().addParamConverter(Player.class, Bukkit::getPlayer, "Online player not found!", playerSupplier);
|
Companion.getCommand2MC().addParamConverter(Player.class, Bukkit::getPlayer, "Online player not found!", playerSupplier);
|
||||||
if (writePluginList.get()) {
|
if (writePluginList.get()) {
|
||||||
try {
|
try {
|
||||||
Files.write(new File("plugins", "plugins.txt").toPath(), Arrays.stream(Bukkit.getPluginManager().getPlugins()).map(p -> (CharSequence) p.getDataFolder().getName())::iterator);
|
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.TBMCCoreAPI
|
||||||
import buttondevteam.lib.architecture.Component.Companion.updateConfig
|
import buttondevteam.lib.architecture.Component.Companion.updateConfig
|
||||||
import buttondevteam.lib.chat.Command2MC
|
import buttondevteam.lib.chat.Command2MC
|
||||||
import buttondevteam.lib.chat.Command2MC.registerCommand
|
|
||||||
import buttondevteam.lib.chat.Command2MC.unregisterCommands
|
|
||||||
import buttondevteam.lib.chat.ICommand2MC
|
import buttondevteam.lib.chat.ICommand2MC
|
||||||
import lombok.AccessLevel
|
import lombok.AccessLevel
|
||||||
import lombok.Getter
|
import lombok.Getter
|
||||||
|
@ -22,8 +20,7 @@ import java.util.function.Function
|
||||||
|
|
||||||
@HasConfig(global = true)
|
@HasConfig(global = true)
|
||||||
abstract class ButtonPlugin : JavaPlugin() {
|
abstract class ButtonPlugin : JavaPlugin() {
|
||||||
@Getter(AccessLevel.PROTECTED)
|
protected val iConfig = IHaveConfig { saveConfig() }
|
||||||
private val iConfig = IHaveConfig { saveConfig() }
|
|
||||||
private var yaml: CommentedConfiguration? = null
|
private var yaml: CommentedConfiguration? = null
|
||||||
|
|
||||||
@Getter(AccessLevel.PROTECTED)
|
@Getter(AccessLevel.PROTECTED)
|
||||||
|
@ -74,7 +71,7 @@ abstract class ButtonPlugin : JavaPlugin() {
|
||||||
ComponentManager.unregComponents(this)
|
ComponentManager.unregComponents(this)
|
||||||
pluginDisable()
|
pluginDisable()
|
||||||
if (ConfigData.saveNow(config)) logger.info("Saved configuration changes.")
|
if (ConfigData.saveNow(config)) logger.info("Saved configuration changes.")
|
||||||
ButtonPlugin.getCommand2MC().unregisterCommands(this)
|
command2MC.unregisterCommands(this)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
TBMCCoreAPI.SendException("Error while disabling plugin $name!", e, this)
|
TBMCCoreAPI.SendException("Error while disabling plugin $name!", e, this)
|
||||||
}
|
}
|
||||||
|
@ -122,7 +119,7 @@ abstract class ButtonPlugin : JavaPlugin() {
|
||||||
|
|
||||||
override fun getConfig(): FileConfiguration {
|
override fun getConfig(): FileConfiguration {
|
||||||
if (yaml == null) justReload()
|
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() {
|
override fun saveConfig() {
|
||||||
|
@ -140,16 +137,15 @@ abstract class ButtonPlugin : JavaPlugin() {
|
||||||
*/
|
*/
|
||||||
fun registerCommand(command: ICommand2MC) {
|
fun registerCommand(command: ICommand2MC) {
|
||||||
command.registerToPlugin(this)
|
command.registerToPlugin(this)
|
||||||
ButtonPlugin.getCommand2MC().registerCommand(command)
|
command2MC.registerCommand(command)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
@Target(AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS)
|
||||||
annotation class ConfigOpts(val disableConfigGen: Boolean = false)
|
annotation class ConfigOpts(val disableConfigGen: Boolean = false)
|
||||||
companion object {
|
companion object {
|
||||||
@Getter //Needs to be static as we don't know the plugin when a command is handled
|
//Needs to be static as we don't know the plugin when a command is handled
|
||||||
|
val command2MC = Command2MC()
|
||||||
private val command2MC = Command2MC()
|
|
||||||
fun configGenAllowed(obj: Any): Boolean {
|
fun configGenAllowed(obj: Any): Boolean {
|
||||||
return !Optional.ofNullable(obj.javaClass.getAnnotation(ConfigOpts::class.java))
|
return !Optional.ofNullable(obj.javaClass.getAnnotation(ConfigOpts::class.java))
|
||||||
.map(Function<ConfigOpts, Boolean> { obj: ConfigOpts -> obj.disableConfigGen() }).orElse(false)
|
.map(Function<ConfigOpts, Boolean> { obj: ConfigOpts -> obj.disableConfigGen() }).orElse(false)
|
||||||
|
|
|
@ -2,9 +2,8 @@ package buttondevteam.lib.chat
|
||||||
|
|
||||||
import buttondevteam.core.MainPlugin
|
import buttondevteam.core.MainPlugin
|
||||||
import buttondevteam.lib.TBMCCoreAPI
|
import buttondevteam.lib.TBMCCoreAPI
|
||||||
import buttondevteam.lib.chat.Command2.Subcommand
|
|
||||||
import buttondevteam.lib.chat.commands.*
|
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.CommandDispatcher
|
||||||
import com.mojang.brigadier.arguments.*
|
import com.mojang.brigadier.arguments.*
|
||||||
import com.mojang.brigadier.builder.ArgumentBuilder
|
import com.mojang.brigadier.builder.ArgumentBuilder
|
||||||
|
@ -15,8 +14,6 @@ import com.mojang.brigadier.tree.CommandNode
|
||||||
import com.mojang.brigadier.tree.LiteralCommandNode
|
import com.mojang.brigadier.tree.LiteralCommandNode
|
||||||
import lombok.RequiredArgsConstructor
|
import lombok.RequiredArgsConstructor
|
||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
import org.javatuples.Pair
|
|
||||||
import org.javatuples.Triplet
|
|
||||||
import java.lang.reflect.Method
|
import java.lang.reflect.Method
|
||||||
import java.util.function.Function
|
import java.util.function.Function
|
||||||
import java.util.function.Predicate
|
import java.util.function.Predicate
|
||||||
|
@ -90,7 +87,7 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender> {
|
||||||
</T> */
|
</T> */
|
||||||
open fun <T> addParamConverter(cl: Class<T>, converter: Function<String, T>, errormsg: String,
|
open fun <T> addParamConverter(cl: Class<T>, converter: Function<String, T>, errormsg: String,
|
||||||
allSupplier: Supplier<Iterable<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 {
|
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
|
//TODO: Add to the help
|
||||||
private fun processSenderType(sender: TP, sd: SubcommandData<TC, TP>, params: ArrayList<Any>): Boolean {
|
open fun convertSenderType(sender: TP, senderType: Class<*>): Any? {
|
||||||
val sendertype = sd.senderType
|
//The command either expects a CommandSender or it is a Player, or some other expected type
|
||||||
val cg: ChromaGamerBase
|
if (senderType.isAssignableFrom(sender.javaClass)) return sender
|
||||||
if (sendertype.isAssignableFrom(sender.javaClass)) params.add(sender) //The command either expects a CommandSender or it is a Player, or some other expected type
|
return null
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -146,17 +131,18 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender> {
|
||||||
*/
|
*/
|
||||||
protected fun registerCommandSuper(command: TC): LiteralCommandNode<TP> {
|
protected fun registerCommandSuper(command: TC): LiteralCommandNode<TP> {
|
||||||
var mainCommandNode: LiteralCommandNode<TP>? = null
|
var mainCommandNode: LiteralCommandNode<TP>? = null
|
||||||
for (meth in command.javaClass.getMethods()) {
|
for (meth in command.javaClass.methods) {
|
||||||
val ann = meth.getAnnotation<Subcommand>(Subcommand::class.java) ?: continue
|
val ann = meth.getAnnotation(Subcommand::class.java) ?: continue
|
||||||
val methodPath = CommandUtils.getCommandPath(meth.name, ' ')
|
val methodPath = CommandUtils.getCommandPath(meth.name, ' ')
|
||||||
val result = registerNodeFromPath(command!!.commandPath + methodPath)
|
val (lastNode, mainNode, remainingPath) = registerNodeFromPath(command.commandPath + methodPath)
|
||||||
result.value0.addChild(getExecutableNode(meth, command, ann, result.value2, CommandArgumentHelpManager(command)))
|
lastNode.addChild(getExecutableNode(meth, command, ann, remainingPath, CommandArgumentHelpManager(command)))
|
||||||
if (mainCommandNode == null) mainCommandNode = result.value1 else if (result.value1!!.name != mainCommandNode.name) {
|
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)
|
MainPlugin.Instance.logger.warning("Multiple commands are defined in the same class! This is not supported. Class: " + command.javaClass.simpleName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mainCommandNode == null) {
|
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
|
return mainCommandNode
|
||||||
}
|
}
|
||||||
|
@ -170,18 +156,18 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender> {
|
||||||
* @return The executable node
|
* @return The executable node
|
||||||
*/
|
*/
|
||||||
private fun getExecutableNode(method: Method, command: TC, ann: Subcommand, path: String, argHelpManager: CommandArgumentHelpManager<TC, TP>): LiteralCommandNode<TP> {
|
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, _) = getCommandParametersAndSender(method, argHelpManager) // Param order is important
|
||||||
val params = paramsAndSenderType.value0
|
|
||||||
val paramMap = HashMap<String, CommandArgument?>()
|
val paramMap = HashMap<String, CommandArgument?>()
|
||||||
for (param in params) {
|
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)
|
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) }
|
.helps(command.getHelpText(method, ann)).permits { sender: TP -> hasPermission(sender, command, method) }
|
||||||
.executes { context: CommandContext<TP> -> executeCommand(context) }
|
.executes { context: CommandContext<TP> -> executeCommand(context) }
|
||||||
var parent: ArgumentBuilder<TP, *> = node
|
var parent: ArgumentBuilder<TP, *> = node
|
||||||
for (param in params) { // Register parameters in the right order
|
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()
|
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,
|
* @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): 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()
|
val split = path.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||||
var parent: CommandNode<TP> = dispatcher.root
|
var parent: CommandNode<TP> = dispatcher.root
|
||||||
var mainCommand: LiteralCommandNode<TP>? = null
|
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 (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
|
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
|
* @return Parameter data objects and the sender type
|
||||||
* @throws RuntimeException If there is no sender parameter declared in the method
|
* @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
|
val parameters = method.parameters
|
||||||
if (parameters.size == 0) throw RuntimeException("No sender parameter for method '$method'")
|
if (parameters.isEmpty()) throw RuntimeException("No sender parameter for method '$method'")
|
||||||
val ret = arrayOfNulls<CommandArgument>(parameters.size)
|
|
||||||
val usage = argHelpManager.getParameterHelpForMethod(method)
|
val usage = argHelpManager.getParameterHelpForMethod(method)
|
||||||
val paramNames = usage?.split(" ".toRegex())?.dropLastWhile { it.isEmpty() }?.toTypedArray()
|
val paramNames = usage?.split(" ")
|
||||||
for (i in 1 until parameters.size) {
|
return Pair(parameters.zip(paramNames ?: (1 until parameters.size).map { i -> "param$i" })
|
||||||
val numAnn = parameters[i].getAnnotation(NumberArg::class.java)
|
.map { (param, name) ->
|
||||||
ret[i - 1] = CommandArgument(paramNames?.get(i) ?: "param$i", parameters[i].type,
|
val numAnn = param.getAnnotation(NumberArg::class.java)
|
||||||
parameters[i].isVarArgs || parameters[i].isAnnotationPresent(TextArg::class.java),
|
CommandArgument(name, param.type,
|
||||||
if (numAnn == null) null else Pair(numAnn.lowerLimit(), numAnn.upperLimit()),
|
param.isVarArgs || param.isAnnotationPresent(TextArg::class.java),
|
||||||
parameters[i].isAnnotationPresent(OptionalArg::class.java),
|
if (numAnn == null) Pair(Double.MIN_VALUE, Double.MAX_VALUE) else Pair(numAnn.lowerLimit, numAnn.upperLimit),
|
||||||
paramNames?.get(i) ?: "param$i") // TODO: Description (JavaDoc?)
|
param.isAnnotationPresent(OptionalArg::class.java),
|
||||||
}
|
name)
|
||||||
return Pair(ret, parameters[0].type)
|
}, parameters[0].type)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -238,13 +223,24 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender> {
|
||||||
* @param arg Our representation of the command argument
|
* @param arg Our representation of the command argument
|
||||||
* @return The Brigadier 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 ptype = arg!!.type
|
||||||
val lowerLimit: Number = arg.limits.value0
|
val (lowerLimit, upperLimit) = arg.limits
|
||||||
val upperLimit: Number = arg.limits.value1
|
return if (arg.greedy) StringArgumentType.greedyString()
|
||||||
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 {
|
else if (ptype == String::class.java) StringArgumentType.word()
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
// TODO: WIP
|
// 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
|
if (processSenderType(sender, sd, params, parameterTypes)) return; // Checks if the sender is the wrong type
|
||||||
val args = parsed.getContext().getArguments();
|
val args = parsed.getContext().getArguments();
|
||||||
for (var arg : sd.arguments.entrySet()) {*/
|
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
|
abstract fun hasPermission(sender: TP, command: TC, subcommand: Method?): Boolean
|
||||||
val commandsText: Array<String>
|
val commandsText: Array<String> get() = commandHelp.toTypedArray()
|
||||||
get() = commandHelp.toTypedArray()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all registered command nodes. This returns all registered Chroma commands with all the information about them.
|
* 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
|
* @return A set of command node objects containing the commands
|
||||||
*/
|
*/
|
||||||
val commandNodes: Set<CoreCommandNode<TP, TC?>?>
|
val commandNodes: Set<CoreCommandNode<TP, TC>>
|
||||||
get() = dispatcher.root.children.stream().map { node: CommandNode<TP>? -> node as CoreCommandNode<TP, TC?>? }.collect(Collectors.toUnmodifiableSet())
|
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.
|
* 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
|
* @return A command node
|
||||||
*/
|
*/
|
||||||
fun getCommandNode(command: String?): CoreCommandNode<TP, TC> {
|
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
|
* @param command The command class (object) to unregister
|
||||||
*/
|
*/
|
||||||
fun unregisterCommand(command: ICommand2<TP>) {
|
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
|
* @param condition The condition for removing a given command
|
||||||
*/
|
*/
|
||||||
fun unregisterCommandIf(condition: Predicate<CoreCommandNode<TP, TC>?>, nested: Boolean) {
|
fun unregisterCommandIf(condition: Predicate<CoreCommandNode<TP, TC>>, nested: Boolean) {
|
||||||
dispatcher.root.children.removeIf { node: CommandNode<TP>? -> condition.test(node as CoreCommandNode<TP, TC>?) }
|
dispatcher.root.children.removeIf { node: CommandNode<TP> -> condition.test(node.core()) }
|
||||||
if (nested) for (child in dispatcher.root.children) unregisterCommandIf(condition, child as CoreCommandNode<TP, TC>)
|
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
|
// 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)
|
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.event.Listener
|
||||||
import org.bukkit.permissions.Permission
|
import org.bukkit.permissions.Permission
|
||||||
import org.bukkit.permissions.PermissionDefault
|
import org.bukkit.permissions.PermissionDefault
|
||||||
import org.javatuples.Triplet
|
|
||||||
import java.lang.reflect.Method
|
import java.lang.reflect.Method
|
||||||
import java.lang.reflect.Parameter
|
import java.lang.reflect.Parameter
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -36,7 +35,7 @@ import java.util.function.BiConsumer
|
||||||
import java.util.function.Function
|
import java.util.function.Function
|
||||||
import java.util.function.Supplier
|
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.
|
* 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)
|
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) {
|
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<*>) {
|
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
|
* @param sender The sender to use
|
||||||
* @return A user as returned by a converter or null if none can supply it
|
* @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) {
|
for (val converter : senderConverters) {
|
||||||
val ocg = converter.apply(sender);
|
val ocg = converter.apply(sender);
|
||||||
if (ocg.isPresent())
|
if (ocg.isPresent())
|
||||||
|
|
Loading…
Reference in a new issue