Created
December 3, 2018 11:58
-
-
Save DevSrSouza/684b59a95eb92fa9c44de859fe64d1d7 to your computer and use it in GitHub Desktop.
Old idea of Arguments for KotlinBukkitAPI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package br.com.devsrsouza.kotlinbukkitapi.dsl.command | |
import br.com.devsrsouza.kotlinbukkitapi.extensions.text.asText | |
import br.com.devsrsouza.kotlinbukkitapi.extensions.text.color | |
import br.com.devsrsouza.kotlinbukkitapi.extensions.text.unaryPlus | |
import net.md_5.bungee.api.chat.TextComponent | |
import org.bukkit.Bukkit | |
import org.bukkit.ChatColor | |
import org.bukkit.Location | |
import org.bukkit.World | |
import org.bukkit.command.CommandSender | |
import org.bukkit.entity.Player | |
import kotlin.reflect.KClass | |
/** | |
* DSL | |
*/ | |
typealias ArgumentExecutorBlock<T> = ArgumentExecutor.(T) -> Unit | |
typealias ParseExceptionBlock = ParseException.() -> String | |
interface Argumentable { | |
var argument: Argument<*>? | |
fun <T : Any> argument(factoryType: KClass<T>, block: ArgumentExecutorBlock<T>): Argument<T> { | |
val factory = ArgumentController[factoryType] | |
if(factory != null) { | |
return argumentByFactory(factory, block) | |
} else throw IllegalArgumentException("Not found ArgumentFactory registred for ${factoryType.simpleName} type") | |
} | |
fun <T : Any> argumentByFactory(factory: ArgumentFactory<T>, block: ArgumentExecutorBlock<T>) | |
= Argument(factory, block).also { this.argument = it } | |
} | |
inline fun <reified T : Any> Argumentable.argument(noinline block: ArgumentExecutorBlock<T>) | |
= argument(T::class, block) | |
open class ArgumentExecutor(internal val sender: CommandSender, val argumentLabel: String, val args: Array<out String>) : Argumentable { | |
override var argument: Argument<*>? = null | |
} | |
class ParseException(val id: Int) : Exception() | |
class ParseBox<T>(val value: T, val argsUsage: Int) | |
class Argument<T : Any>(val argumentFactory: ArgumentFactory<T>, val argumentExecutor: ArgumentExecutorBlock<T>, private var whenErrorBlock: ParseExceptionBlock? = null) { | |
infix fun whenError(block: ParseExceptionBlock) { | |
whenErrorBlock = block | |
} | |
internal fun runArgumentExecutor(sender: CommandSender, label: String, args: Array<out String>) { | |
if(argumentFactory.minArgs > args.size) { | |
sender.sendMessage(+"&c/${label} ${argumentFactory.usageFormat}") | |
return | |
} | |
try { | |
val box = argumentFactory.parser(sender, args) | |
val argumentLabel = label + " " + args.slice(0 until box.argsUsage).joinToString(" ") | |
ArgumentExecutor(sender, argumentLabel, args.sliceArray(box.argsUsage until args.size)).apply { | |
argumentExecutor(box.value) | |
argument?.also { | |
it.runArgumentExecutor(sender, this.argumentLabel, this.args) | |
} | |
} | |
}catch (e: ParseException) { | |
if(whenErrorBlock != null) { | |
sender.sendMessage(whenErrorBlock?.invoke(e)) | |
} else { | |
sender.sendMessage(argumentFactory.whenError(e)) | |
} | |
} | |
} | |
} | |
abstract class ArgumentFactory<T : Any>(val kclass: KClass<T>, val minArgs: Int, val usageFormat: String) { | |
abstract fun parser(sender: CommandSender, args: Array<out String>): ParseBox<T> | |
abstract fun parserTabComplete(args: Array<String>): List<String> | |
abstract fun whenError(error: ParseException): String | |
fun register() = ArgumentController.register(this) | |
} | |
class SimpleArgumentFactory<T : Any>(kclass: KClass<T>, | |
minArgs: Int, | |
usageFormat: String, | |
private val parser: (args: Array<out String>) -> ParseBox<T>, | |
private val errorMessage: (error: ParseException) -> String) | |
: ArgumentFactory<T>(kclass, minArgs, usageFormat) { | |
override fun parser(sender: CommandSender, args: Array<out String>) = parser.invoke(args) | |
override fun whenError(error: ParseException) = errorMessage.invoke(error) | |
override fun parserTabComplete(args: Array<String>): List<String> { | |
return emptyList() // TODO | |
} | |
} | |
object PlayerArgumentFactory : ArgumentFactory<Player>(Player::class, 1, "[player name]") { | |
override fun parser(sender: CommandSender, args: Array<out String>): ParseBox<Player> { | |
return ParseBox( | |
args.get(0).let { Bukkit.getPlayerExact(it) } ?: throw ParseException(1), | |
1 | |
) | |
} | |
override fun whenError(error: ParseException): String { | |
return when (error.id) { | |
1 -> +"&cPlayer not found" | |
else -> "&cError not treated. ${error.message}" | |
} | |
} | |
override fun parserTabComplete(args: Array<String>): List<String> { | |
return emptyList() // TODO | |
} | |
} | |
object LocationArgumentFactory : ArgumentFactory<Location>(Location::class, 1, "[x] [y] [z] [world]") { | |
override fun parser(sender: CommandSender, args: Array<out String>): ParseBox<Location> { | |
val arg1 = args[0] | |
if(arg1.startsWith("player:", true)) { | |
return ParseBox( | |
arg1.split(":").getOrNull(1)?.let { Bukkit.getPlayerExact(it) }?.location ?: throw ParseException(1), | |
1 | |
) | |
} else { | |
val arg2 = args.getOrNull(1) | |
val arg3 = args.getOrNull(2) | |
val arg4 = args.getOrNull(3) | |
if(sender is Player && (arg4 == null || Bukkit.getWorld(arg4) == null)) { | |
return ParseBox( | |
Location(sender.world, arg1.toDoubleOrNull() ?: throw ParseException(2), | |
arg2?.toDoubleOrNull() ?: throw ParseException(3), | |
arg3?.toDoubleOrNull() ?: throw ParseException(4)), | |
3 | |
) | |
} else { | |
return ParseBox( | |
Location(Bukkit.getWorld(arg4 ?: throw ParseException(5)) ?: throw ParseException(6), | |
arg1.toDoubleOrNull() ?: throw ParseException(2), | |
arg2?.toDoubleOrNull() ?: throw ParseException(3), | |
arg3?.toDoubleOrNull() ?: throw ParseException(4)), | |
4 | |
) | |
} | |
} | |
} | |
override fun whenError(error: ParseException): String { | |
return when (error.id) { | |
1 -> "TENHO QUE FAZER OS OUTROS" | |
else -> "&cError not treated. ${error.message}" | |
} | |
} | |
override fun parserTabComplete(args: Array<String>): List<String> { | |
return emptyList() // TODO | |
} | |
} | |
object TextArgumentFactory : ArgumentFactory<String>(String::class, 1, "[text]") { | |
override fun parser(sender: CommandSender, args: Array<out String>): ParseBox<String> { | |
return ParseBox( | |
args.joinToString(" "), | |
args.size | |
) | |
} | |
override fun whenError(error: ParseException): String { | |
return "&cError not treated. ${error.message}" | |
} | |
override fun parserTabComplete(args: Array<String>): List<String> { | |
return emptyList() | |
} | |
} | |
internal fun MutableList<ArgumentFactory<*>>.register(factory: ArgumentFactory<*>): Boolean { | |
if(find { it.kclass.equals(factory.kclass) } != null) return false | |
add(factory) | |
return true | |
} | |
object ArgumentController { | |
private val arguments: MutableList<ArgumentFactory<*>> = mutableListOf() | |
init { | |
register(PlayerArgumentFactory) | |
register(TextArgumentFactory) | |
register(LocationArgumentFactory) | |
} | |
fun register(factory: ArgumentFactory<*>) = arguments.register(factory) | |
operator fun <T : Any> get(clazz: KClass<T>) : ArgumentFactory<T>? { | |
return arguments.find { it.kclass.equals(clazz) } as? ArgumentFactory<T>? | |
} | |
internal fun getArguments(): List<ArgumentFactory<*>> = arguments | |
} | |
fun meuCommand() { | |
command("lala") { | |
executorPlayer { | |
argument<Player> { target -> | |
argument<Location> { loc -> // x y z / player:SrSouza / x y z world | |
argumentByFactory(TextArgumentFactory) { texto -> | |
target.teleport(loc) | |
target.sendMessage(+texto) | |
} | |
} | |
} whenError { //ParseException.() -> String | |
when (id) { | |
1 -> +"&cJogador não encontrado." | |
else -> "&cOcorreu um erro que não foi tratado. $message" | |
} | |
} | |
} | |
} | |
command("broadcast") { | |
executor { | |
argumentByFactory(TextArgumentFactory) { message -> | |
Bukkit.broadcastMessage(+message) | |
} | |
} | |
} | |
command("tell") { | |
executor { | |
argument<Player> { target -> | |
argumentByFactory(TextArgumentFactory) { message -> | |
target.sendMessage(+message) | |
} | |
} | |
} | |
tabComplete { | |
arguments(Player::class) | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package br.com.devsrsouza.kotlinbukkitapi.dsl.command | |
import br.com.devsrsouza.kotlinbukkitapi.KotlinBukkitAPI | |
import br.com.devsrsouza.kotlinbukkitapi.extensions.text.asText | |
import net.md_5.bungee.api.chat.TextComponent | |
import org.bukkit.Bukkit | |
import org.bukkit.command.Command | |
import org.bukkit.command.CommandSender | |
import org.bukkit.command.SimpleCommandMap | |
import org.bukkit.entity.Player | |
import org.bukkit.plugin.Plugin | |
private val serverCommands: SimpleCommandMap by lazy { | |
val packageName = Bukkit.getServer().javaClass.getPackage().getName() | |
val version = packageName.substring(packageName.lastIndexOf('.') + 1) | |
val bukkitclass = Class.forName("org.bukkit.craftbukkit.$version.CraftServer") | |
val f = bukkitclass.getDeclaredField("commandMap") | |
f.isAccessible = true | |
f.get(Bukkit.getServer()) as SimpleCommandMap | |
} | |
typealias ExecutorBlock = Executor<CommandSender>.() -> Unit | |
typealias ExecutorPlayerBlock = Executor<Player>.() -> Unit | |
typealias TabCompleterBlock = TabCompleter.() -> MutableList<String> | |
typealias CommandMaker = KCommand.() -> Unit | |
class CommandException(val senderMessage: TextComponent = "".asText(), val execute: () -> Unit = {}) : RuntimeException() { | |
constructor(senderMessage: String = "", execute: () -> Unit = {}) : this(senderMessage.asText(), execute) | |
} | |
fun simpleCommand(name: String, vararg aliases: String = arrayOf(), | |
description: String = "", | |
plugin: Plugin = KotlinBukkitAPI.INSTANCE, | |
block: ExecutorBlock) = command(name, plugin) { | |
if (description.isNotBlank()) this.description = description | |
if (aliases.isNotEmpty()) this.aliases = aliases.toList() | |
executor(block) | |
} | |
fun command(name: String, | |
plugin: Plugin = KotlinBukkitAPI.INSTANCE, | |
block: CommandMaker) = KCommand(name).apply(block).apply { | |
register(plugin) | |
} | |
fun Command.register(plugin: Plugin = KotlinBukkitAPI.INSTANCE) { | |
serverCommands.register(plugin.name, this) | |
} | |
fun Command.unregister() { | |
try { | |
val clazz = serverCommands.javaClass | |
val f = clazz.getDeclaredField("knownCommands") | |
f.isAccessible = true | |
val knownCommands = f.get(serverCommands) as MutableMap<String, Command> | |
val toRemove = ArrayList<String>() | |
for ((key, value) in knownCommands) { | |
if (value === this) { | |
toRemove.add(key) | |
} | |
} | |
for (str in toRemove) { | |
knownCommands.remove(str) | |
} | |
} catch (e: Exception) { | |
e.printStackTrace() | |
} | |
} | |
open class Executor<E : CommandSender>(val sender: E, | |
val label: String, | |
val args: Array<out String>) : Argumentable { | |
override var argument: Argument<*>? = null | |
} | |
class TabCompleter(val sender: CommandSender, | |
val alias: String, | |
val args: Array<out String>) { | |
fun arguments(vararg arguments: Any): MutableList<String> { | |
TODO("FAZER ESSA MERDA AQUI CARAIO") | |
} | |
} | |
open class KCommand(name: String, | |
executor: ExecutorBlock = {} | |
) : org.bukkit.command.Command(name.trim()) { | |
protected open var executor: ExecutorBlock = executor | |
private var executorPlayer: ExecutorPlayerBlock? = null | |
private var tabCompleter: TabCompleterBlock? = null | |
val subCommands: MutableList<KCommand> = mutableListOf() | |
var onlyInGameMessage = "" | |
override fun execute(sender: CommandSender, label: String, args: Array<out String>): Boolean { | |
if (subCommands.isNotEmpty()) { | |
val subCommand = args.getOrNull(0)?.let { arg -> | |
subCommands.find { | |
it.name.equals(arg, true) || | |
it.aliases.find { it.equals(arg, true) } != null | |
} | |
} | |
if (subCommand != null) { | |
subCommand.execute(sender, "$label ${args.get(0)}", args.sliceArray(1 until args.size)) | |
return true | |
} | |
} | |
try { | |
if (executorPlayer != null) { | |
if (sender is Player) { | |
val exc = Executor(sender, label, args) | |
executorPlayer!!.invoke(exc) | |
exc.argument?.runArgumentExecutor(sender, label, args) | |
} else sender.sendMessage(onlyInGameMessage) | |
} else { | |
Executor(sender, label, args).apply { | |
executor() | |
argument?.runArgumentExecutor(sender, label, args) | |
} | |
} | |
} catch (ex: CommandException) { | |
if (ex.senderMessage.isNotBlank()) sender.sendMessage(ex.senderMessage) | |
ex.execute() | |
} | |
return true | |
} | |
override fun tabComplete(sender: CommandSender, alias: String, args: Array<out String>): MutableList<String> { | |
return if (tabCompleter != null) { | |
tabCompleter!!.invoke(TabCompleter(sender, alias, args)) | |
} else { | |
defaultTabComplete(sender, alias, args) | |
} | |
} | |
open fun defaultTabComplete(sender: CommandSender, alias: String, args: Array<out String>): MutableList<String> { | |
if (args.size > 1) { | |
val subCommand = subCommands.find { it.name.equals(args.getOrNull(0), true) } | |
if (subCommand != null) { | |
return subCommand.tabComplete(sender, args.get(0), args.sliceArray(1 until args.size)) | |
} else { | |
emptyList<String>().toMutableList() | |
} | |
} else if (args.size > 0) { | |
return subCommands | |
.filter { it.name.startsWith(args.get(0), true) } | |
.map { it.name } | |
.toMutableList() | |
} | |
return super.tabComplete(sender, alias, args) | |
} | |
open fun command(name: String, block: CommandMaker) { | |
subCommands.add(KCommand(name).also { | |
it.permission = this.permission | |
it.permissionMessage = this.permissionMessage | |
}.apply(block)) | |
} | |
open fun executor(block: ExecutorBlock) { | |
executor = block | |
} | |
open fun executorPlayer(block: ExecutorPlayerBlock) { | |
executorPlayer = block | |
} | |
open fun tabComplete(block: TabCompleterBlock) { | |
tabCompleter = block | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment