From ecbbfb5a71e6199c13515c96e85dfb1917e6f384 Mon Sep 17 00:00:00 2001 From: Jakob K Date: Sun, 27 Jun 2021 23:41:34 +0200 Subject: [PATCH] Add brigardier support --- .../kspigot/commands/BrigardierSupport.kt | 23 +++++ .../kspigot/commands/BrigardierWrapper.kt | 93 +++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 src/main/kotlin/net/axay/kspigot/commands/BrigardierSupport.kt create mode 100644 src/main/kotlin/net/axay/kspigot/commands/BrigardierWrapper.kt diff --git a/src/main/kotlin/net/axay/kspigot/commands/BrigardierSupport.kt b/src/main/kotlin/net/axay/kspigot/commands/BrigardierSupport.kt new file mode 100644 index 00000000..d2b05af2 --- /dev/null +++ b/src/main/kotlin/net/axay/kspigot/commands/BrigardierSupport.kt @@ -0,0 +1,23 @@ +package net.axay.kspigot.commands + +import com.mojang.brigadier.CommandDispatcher +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import net.axay.kspigot.extensions.server +import net.minecraft.commands.CommandListenerWrapper +import org.bukkit.craftbukkit.v1_17_R1.CraftServer + +object BrigardierSupport { + @PublishedApi + internal val commands = ArrayList>() + + fun registerAll() { + val commandManager = (server as CraftServer).server.commandDispatcher + + val dispatcherField = net.minecraft.commands.CommandDispatcher::class.java.getDeclaredField("g") + dispatcherField.isAccessible = true + @Suppress("UNCHECKED_CAST") + val dispatcher = dispatcherField.get(commandManager) as CommandDispatcher + + commands.forEach { dispatcher.register(it) } + } +} diff --git a/src/main/kotlin/net/axay/kspigot/commands/BrigardierWrapper.kt b/src/main/kotlin/net/axay/kspigot/commands/BrigardierWrapper.kt new file mode 100644 index 00000000..dc670bdc --- /dev/null +++ b/src/main/kotlin/net/axay/kspigot/commands/BrigardierWrapper.kt @@ -0,0 +1,93 @@ +package net.axay.kspigot.commands + +import com.mojang.brigadier.arguments.ArgumentType +import com.mojang.brigadier.builder.ArgumentBuilder +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.builder.RequiredArgumentBuilder +import com.mojang.brigadier.context.CommandContext +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.future.asCompletableFuture +import net.minecraft.commands.CommandListenerWrapper + +/** + * Create a new command. + * + * @param name the name of the root command + * @param register if true, the command will automatically be registered + */ +inline fun command( + name: String, + register: Boolean = true, + builder: LiteralArgumentBuilder.() -> Unit +): LiteralArgumentBuilder = + LiteralArgumentBuilder.literal(name).apply(builder).apply { + if (register) + BrigardierSupport.commands += this + } + +/** + * Add custom execution logic for this command. + */ +inline fun ArgumentBuilder.simpleExecutes( + crossinline executor: (CommandContext) -> Unit +) { + executes wrapped@{ + executor.invoke(it) + return@wrapped 1 + } +} + +/** + * Add a new literal to this command. + * + * @param name the name of the literal + */ +inline fun ArgumentBuilder.literal( + name: String, + builder: LiteralArgumentBuilder.() -> Unit +) { + then(command(name, false, builder)) +} + +/** + * Add an argument. + * + * @param name the name of the argument + * @param type the type of the argument - e.g. IntegerArgumentType.integer() or StringArgumentType.string() + */ +inline fun ArgumentBuilder.argument( + name: String, + type: ArgumentType, + builder: RequiredArgumentBuilder.() -> Unit +) { + then(RequiredArgumentBuilder.argument(name, type).apply(builder)) +} + +private val argumentCoroutineScope = CoroutineScope(Dispatchers.IO) + +/** + * Add custom suspending suggestion logic for an argument. + */ +fun RequiredArgumentBuilder.simpleSuggests( + suggestionBuilder: suspend (CommandContext) -> Iterable? +) { + suggests { context, builder -> + argumentCoroutineScope.async { + suggestionBuilder.invoke(context)?.forEach { + if (it is Int) + builder.suggest(it) + else + builder.suggest(it.toString()) + } + builder.build() + }.asCompletableFuture() + } +} + +/** + * Get the value of this argument. + */ +inline fun CommandContext.getArgument(name: String): T = + getArgument(name, T::class.java)