Greatly improve Brigardier support
This commit is contained in:
@@ -19,7 +19,6 @@ plugins {
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven("https://libraries.minecraft.net")
|
||||
mavenCentral()
|
||||
mavenLocal() // to get the locally available binaries of spigot (use the BuildTools)
|
||||
}
|
||||
@@ -31,8 +30,6 @@ dependencies {
|
||||
api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.2")
|
||||
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1")
|
||||
api("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.5.1")
|
||||
|
||||
api("me.lucko:commodore:1.10")
|
||||
}
|
||||
|
||||
tasks {
|
||||
|
40
src/main/kotlin/net/axay/kspigot/commands/Arguments.kt
Normal file
40
src/main/kotlin/net/axay/kspigot/commands/Arguments.kt
Normal file
@@ -0,0 +1,40 @@
|
||||
package net.axay.kspigot.commands
|
||||
|
||||
import com.mojang.brigadier.arguments.ArgumentType
|
||||
import com.mojang.brigadier.builder.ArgumentBuilder
|
||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder
|
||||
import com.mojang.brigadier.context.CommandContext
|
||||
import net.axay.kspigot.commands.internal.ArgumentTypeUtils
|
||||
import net.axay.kspigot.commands.internal.ServerCommandSource
|
||||
|
||||
/**
|
||||
* Adds 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 <T> ArgumentBuilder<ServerCommandSource, *>.argument(
|
||||
name: String,
|
||||
type: ArgumentType<T>,
|
||||
builder: RequiredArgumentBuilder<ServerCommandSource, T>.() -> Unit = {}
|
||||
): RequiredArgumentBuilder<ServerCommandSource, T> =
|
||||
RequiredArgumentBuilder.argument<ServerCommandSource, T>(name, type).apply(builder).also { then(it) }
|
||||
|
||||
/**
|
||||
* Adds an argument. The argument type will be resolved via the reified
|
||||
* type [T].
|
||||
*
|
||||
* @param name the name of the argument
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <reified T> ArgumentBuilder<ServerCommandSource, *>.argument(
|
||||
name: String,
|
||||
builder: RequiredArgumentBuilder<ServerCommandSource, T>.() -> Unit = {}
|
||||
): RequiredArgumentBuilder<ServerCommandSource, T> =
|
||||
RequiredArgumentBuilder.argument<ServerCommandSource, T>(name, ArgumentTypeUtils.fromReifiedType<T>()).apply(builder).also { then(it) }
|
||||
|
||||
/**
|
||||
* Get the value of this argument.
|
||||
*/
|
||||
inline fun <reified T> CommandContext<ServerCommandSource>.getArgument(name: String): T =
|
||||
getArgument(name, T::class.java)
|
@@ -1,28 +0,0 @@
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
package net.axay.kspigot.commands
|
||||
|
||||
import com.mojang.brigadier.tree.LiteralCommandNode
|
||||
import me.lucko.commodore.CommodoreProvider
|
||||
import net.axay.kspigot.main.PluginInstance
|
||||
|
||||
/**
|
||||
* This class provides Brigardier support. It does that
|
||||
* by using reflection once. Additionally, this class is
|
||||
* using some obfuscated functions.
|
||||
*/
|
||||
object BrigardierSupport {
|
||||
private val provider = if (CommodoreProvider.isSupported()) CommodoreProvider.getCommodore(PluginInstance) else kotlin.run {
|
||||
PluginInstance.logger.severe("Could not initialize Brigardier support on the current Minecraft version! (Requested by ${PluginInstance.name})")
|
||||
null
|
||||
}
|
||||
|
||||
fun register(name: String, brigardierCommand: LiteralCommandNode<*>) {
|
||||
val command = PluginInstance.getCommand(name)
|
||||
if (command == null) {
|
||||
PluginInstance.logger.severe("Could not register command '$name' of plugin ${PluginInstance.name}! Maybe it is missing from the plugin.yml?")
|
||||
return
|
||||
}
|
||||
provider?.register(command, brigardierCommand)
|
||||
}
|
||||
}
|
@@ -1,97 +0,0 @@
|
||||
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.tree.LiteralCommandNode
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
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 be automatically registered
|
||||
* when the plugin is fully enabled
|
||||
*/
|
||||
inline fun command(
|
||||
name: String,
|
||||
register: Boolean = true,
|
||||
builder: LiteralArgumentBuilder<CommandListenerWrapper>.() -> Unit,
|
||||
): LiteralCommandNode<CommandListenerWrapper> =
|
||||
LiteralArgumentBuilder.literal<CommandListenerWrapper>(name).apply(builder).build().apply {
|
||||
if (register)
|
||||
BrigardierSupport.register(name, this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom execution logic for this command.
|
||||
*/
|
||||
inline fun ArgumentBuilder<CommandListenerWrapper, *>.simpleExecutes(
|
||||
crossinline executor: CommandContext.() -> Unit,
|
||||
) {
|
||||
executes wrapped@{
|
||||
executor.invoke(CommandContext(it))
|
||||
return@wrapped 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new literal to this command.
|
||||
*
|
||||
* @param name the name of the literal
|
||||
*/
|
||||
inline fun ArgumentBuilder<CommandListenerWrapper, *>.literal(
|
||||
name: String,
|
||||
builder: LiteralArgumentBuilder<CommandListenerWrapper>.() -> Unit,
|
||||
) = command(name, false, builder).also { then(it) }
|
||||
|
||||
/**
|
||||
* 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 <T> ArgumentBuilder<CommandListenerWrapper, *>.argument(
|
||||
name: String,
|
||||
type: ArgumentType<T>,
|
||||
builder: RequiredArgumentBuilder<CommandListenerWrapper, T>.() -> Unit,
|
||||
): RequiredArgumentBuilder<CommandListenerWrapper, T> =
|
||||
RequiredArgumentBuilder.argument<CommandListenerWrapper, T>(name, type).apply(builder).also { then(it) }
|
||||
|
||||
/**
|
||||
* Add an argument.
|
||||
*
|
||||
* @param name the name of the argument
|
||||
*/
|
||||
inline fun <reified T> ArgumentBuilder<CommandListenerWrapper, *>.argument(
|
||||
name: String,
|
||||
builder: RequiredArgumentBuilder<CommandListenerWrapper, T>.() -> Unit,
|
||||
): RequiredArgumentBuilder<CommandListenerWrapper, T> =
|
||||
RequiredArgumentBuilder.argument<CommandListenerWrapper, T>(name, ArgumentTypeUtils.fromReifiedType<T>()).apply(builder).also { then(it) }
|
||||
|
||||
private val argumentCoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||
|
||||
/**
|
||||
* Add custom suspending suggestion logic for an argument.
|
||||
*/
|
||||
fun RequiredArgumentBuilder<CommandListenerWrapper, *>.simpleSuggests(
|
||||
suggestionBuilder: suspend CommandContext.() -> Iterable<Any?>?,
|
||||
) {
|
||||
suggests { context, builder ->
|
||||
argumentCoroutineScope.async {
|
||||
suggestionBuilder.invoke(CommandContext(context))?.forEach {
|
||||
if (it is Int)
|
||||
builder.suggest(it)
|
||||
else
|
||||
builder.suggest(it.toString())
|
||||
}
|
||||
builder.build()
|
||||
}.asCompletableFuture()
|
||||
}
|
||||
}
|
@@ -2,14 +2,14 @@ package net.axay.kspigot.commands
|
||||
|
||||
import com.mojang.brigadier.context.CommandContext
|
||||
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType
|
||||
import net.minecraft.commands.CommandListenerWrapper
|
||||
import net.axay.kspigot.commands.internal.ServerCommandSource
|
||||
import net.minecraft.network.chat.ChatMessage
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.Server
|
||||
import org.bukkit.World
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
class CommandContext(val nmsContext: CommandContext<CommandListenerWrapper>) {
|
||||
class CommandContext(val nmsContext: CommandContext<ServerCommandSource>) {
|
||||
companion object {
|
||||
private val REQUIRES_PLAYER_EXCEPTION = SimpleCommandExceptionType(ChatMessage("permissions.requires.player"))
|
||||
}
|
||||
|
32
src/main/kotlin/net/axay/kspigot/commands/Creation.kt
Normal file
32
src/main/kotlin/net/axay/kspigot/commands/Creation.kt
Normal file
@@ -0,0 +1,32 @@
|
||||
package net.axay.kspigot.commands
|
||||
|
||||
import com.mojang.brigadier.builder.ArgumentBuilder
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder
|
||||
import net.axay.kspigot.commands.internal.BrigardierSupport
|
||||
import net.axay.kspigot.commands.internal.ServerCommandSource
|
||||
|
||||
/**
|
||||
* Creates 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<ServerCommandSource>.() -> Unit
|
||||
): LiteralArgumentBuilder<ServerCommandSource> =
|
||||
LiteralArgumentBuilder.literal<ServerCommandSource>(name).apply(builder).apply {
|
||||
if (register)
|
||||
BrigardierSupport.commands += this
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new literal to this command.
|
||||
*
|
||||
* @param name the name of the literal
|
||||
*/
|
||||
inline fun ArgumentBuilder<ServerCommandSource, *>.literal(
|
||||
name: String,
|
||||
builder: LiteralArgumentBuilder<ServerCommandSource>.() -> Unit = {}
|
||||
) = command(name, false, builder).also { then(it) }
|
44
src/main/kotlin/net/axay/kspigot/commands/Execution.kt
Normal file
44
src/main/kotlin/net/axay/kspigot/commands/Execution.kt
Normal file
@@ -0,0 +1,44 @@
|
||||
package net.axay.kspigot.commands
|
||||
|
||||
import com.mojang.brigadier.Command
|
||||
import com.mojang.brigadier.builder.ArgumentBuilder
|
||||
import net.axay.kspigot.commands.internal.ServerCommandSource
|
||||
|
||||
/**
|
||||
* Adds execution logic to this command. The place where this function
|
||||
* is called matters, as this defines for which path in the command tree
|
||||
* this executor should be called.
|
||||
*
|
||||
* @see com.mojang.brigadier.builder.ArgumentBuilder.executes
|
||||
*/
|
||||
inline infix fun ArgumentBuilder<ServerCommandSource, *>.runs(
|
||||
crossinline executor: CommandContext.() -> Unit,
|
||||
) = this.apply {
|
||||
executes wrapped@{
|
||||
executor.invoke(CommandContext(it))
|
||||
return@wrapped 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds execution logic to this command. The place where this function
|
||||
* is called matters, as this defines for which path in the command tree
|
||||
* this executor should be called.
|
||||
*
|
||||
* @see com.mojang.brigadier.builder.ArgumentBuilder.executes
|
||||
*/
|
||||
infix fun <S> ArgumentBuilder<S, *>.runs(executor: Command<S>) =
|
||||
this.apply {
|
||||
executes(executor)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom execution logic for this command.
|
||||
*/
|
||||
@Deprecated(
|
||||
"The name 'simpleExecutes' has been superseded by 'runs'.",
|
||||
ReplaceWith("runs { executor.invoke() }")
|
||||
)
|
||||
inline infix fun ArgumentBuilder<ServerCommandSource, *>.simpleExecutes(
|
||||
crossinline executor: CommandContext.() -> Unit,
|
||||
) = runs(executor)
|
25
src/main/kotlin/net/axay/kspigot/commands/Registration.kt
Normal file
25
src/main/kotlin/net/axay/kspigot/commands/Registration.kt
Normal file
@@ -0,0 +1,25 @@
|
||||
package net.axay.kspigot.commands
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder
|
||||
import net.axay.kspigot.annotations.NMS_General
|
||||
import net.axay.kspigot.commands.internal.BrigardierSupport
|
||||
import net.minecraft.commands.CommandListenerWrapper
|
||||
|
||||
/**
|
||||
* Registers this command at the [CommandDispatcher] of the server.
|
||||
*
|
||||
* @param sendToPlayers whether the new command tree should be send to
|
||||
* all players, this is true by default, but you can disable it if you are
|
||||
* calling this function as the server is starting
|
||||
*/
|
||||
@NMS_General
|
||||
fun LiteralArgumentBuilder<CommandListenerWrapper>.register(sendToPlayers: Boolean = true) {
|
||||
if (!BrigardierSupport.executedDefaultRegistration)
|
||||
BrigardierSupport.commands += this
|
||||
else {
|
||||
BrigardierSupport.commandDispatcher.register(this)
|
||||
if (sendToPlayers)
|
||||
BrigardierSupport.updateCommandTree()
|
||||
}
|
||||
}
|
25
src/main/kotlin/net/axay/kspigot/commands/Requires.kt
Normal file
25
src/main/kotlin/net/axay/kspigot/commands/Requires.kt
Normal file
@@ -0,0 +1,25 @@
|
||||
package net.axay.kspigot.commands
|
||||
|
||||
import com.mojang.brigadier.builder.ArgumentBuilder
|
||||
import net.axay.kspigot.commands.internal.ServerCommandSource
|
||||
import org.bukkit.permissions.Permission
|
||||
|
||||
/**
|
||||
* Defines that the given [permission] is required to interact with this
|
||||
* path of the command.
|
||||
*/
|
||||
fun ArgumentBuilder<ServerCommandSource, *>.requiresPermission(permission: String) {
|
||||
requires {
|
||||
it.bukkitSender.hasPermission(permission)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines that the given [permission] is required to interact with this
|
||||
* path of the command.
|
||||
*/
|
||||
fun ArgumentBuilder<ServerCommandSource, *>.requiresPermission(permission: Permission) {
|
||||
requires {
|
||||
it.bukkitSender.hasPermission(permission)
|
||||
}
|
||||
}
|
185
src/main/kotlin/net/axay/kspigot/commands/Suggestions.kt
Normal file
185
src/main/kotlin/net/axay/kspigot/commands/Suggestions.kt
Normal file
@@ -0,0 +1,185 @@
|
||||
package net.axay.kspigot.commands
|
||||
|
||||
import com.mojang.brigadier.Message
|
||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder
|
||||
import com.mojang.brigadier.context.CommandContext
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.future.asCompletableFuture
|
||||
|
||||
@PublishedApi
|
||||
internal val argumentCoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||
|
||||
/**
|
||||
* Suggest the value which is the result of the [suggestionBuilder].
|
||||
*/
|
||||
inline fun <S> RequiredArgumentBuilder<S, *>.suggestSingle(
|
||||
crossinline suggestionBuilder: (CommandContext<S>) -> Any?
|
||||
) {
|
||||
suggests { context, builder ->
|
||||
builder.applyAny(suggestionBuilder(context))
|
||||
builder.buildFuture()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggest the value which is the result of the [suggestionBuilder].
|
||||
* Additionaly, a separate tooltip associated with the suggestion
|
||||
* will be shown as well.
|
||||
*/
|
||||
inline fun <S> RequiredArgumentBuilder<S, *>.suggestSingleWithTooltip(
|
||||
crossinline suggestionBuilder: (CommandContext<S>) -> Pair<Any, Message>?
|
||||
) {
|
||||
suggests { context, builder ->
|
||||
builder.applyAnyWithTooltip(suggestionBuilder(context))
|
||||
builder.buildFuture()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggest the value which is the result of the [suggestionBuilder].
|
||||
*
|
||||
* @param coroutineScope the [CoroutineScope] where the suggestion should be built in - an async scope by default
|
||||
*/
|
||||
inline fun <S> RequiredArgumentBuilder<S, *>.suggestSingleSuspending(
|
||||
coroutineScope: CoroutineScope = argumentCoroutineScope,
|
||||
crossinline suggestionBuilder: suspend (CommandContext<S>) -> Any?
|
||||
) {
|
||||
suggests { context, builder ->
|
||||
coroutineScope.async {
|
||||
builder.applyAny(suggestionBuilder(context))
|
||||
builder.build()
|
||||
}.asCompletableFuture()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggest the value which is the result of the [suggestionBuilder].
|
||||
* Additionaly, a separate tooltip associated with the suggestion
|
||||
* will be shown as well.
|
||||
*
|
||||
* @param coroutineScope the [CoroutineScope] where the suggestion should be built in - an async scope by default
|
||||
*/
|
||||
inline fun <S> RequiredArgumentBuilder<S, *>.suggestSingleWithTooltipSuspending(
|
||||
coroutineScope: CoroutineScope = argumentCoroutineScope,
|
||||
crossinline suggestionBuilder: suspend (CommandContext<S>) -> Pair<Any?, Message>?
|
||||
) {
|
||||
suggests { context, builder ->
|
||||
coroutineScope.async {
|
||||
builder.applyAnyWithTooltip(suggestionBuilder(context))
|
||||
builder.build()
|
||||
}.asCompletableFuture()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggest the entries of the iterable which is the result of the
|
||||
* [suggestionsBuilder].
|
||||
*/
|
||||
inline fun <S> RequiredArgumentBuilder<S, *>.suggestList(
|
||||
crossinline suggestionsBuilder: (CommandContext<S>) -> Iterable<Any?>?
|
||||
) {
|
||||
suggests { context, builder ->
|
||||
builder.applyIterable(suggestionsBuilder(context))
|
||||
builder.buildFuture()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggest the entries of the iterable which is the result of the
|
||||
* [suggestionsBuilder].
|
||||
* Additionaly, a separate tooltip associated with each suggestion
|
||||
* will be shown as well.
|
||||
*/
|
||||
inline fun <S> RequiredArgumentBuilder<S, *>.suggestListWithTooltips(
|
||||
crossinline suggestionsBuilder: (CommandContext<S>) -> Iterable<Pair<Any?, Message>?>?
|
||||
) {
|
||||
suggests { context, builder ->
|
||||
builder.applyIterableWithTooltips(suggestionsBuilder(context))
|
||||
builder.buildFuture()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggest the entries of the iterable which is the result of the
|
||||
* [suggestionsBuilder].
|
||||
*
|
||||
* @param coroutineScope the [CoroutineScope] where the suggestions should be built in - an async scope by default
|
||||
*/
|
||||
inline fun <S> RequiredArgumentBuilder<S, *>.suggestListSuspending(
|
||||
coroutineScope: CoroutineScope = argumentCoroutineScope,
|
||||
crossinline suggestionsBuilder: suspend (CommandContext<S>) -> Iterable<Any?>?
|
||||
) {
|
||||
suggests { context, builder ->
|
||||
coroutineScope.async {
|
||||
builder.applyIterable(suggestionsBuilder(context))
|
||||
builder.build()
|
||||
}.asCompletableFuture()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggest the entries of the iterable which is the result of the
|
||||
* [suggestionsBuilder].
|
||||
* Additionaly, a separate tooltip associated with each suggestion
|
||||
* will be shown as well.
|
||||
*
|
||||
* @param coroutineScope the [CoroutineScope] where the suggestions should be built in - an async scope by default
|
||||
*/
|
||||
inline fun <S> RequiredArgumentBuilder<S, *>.suggestListWithTooltipsSuspending(
|
||||
coroutineScope: CoroutineScope = argumentCoroutineScope,
|
||||
crossinline suggestionsBuilder: (CommandContext<S>) -> Iterable<Pair<Any?, Message>?>?
|
||||
) {
|
||||
suggests { context, builder ->
|
||||
coroutineScope.async {
|
||||
builder.applyIterableWithTooltips(suggestionsBuilder(context))
|
||||
builder.build()
|
||||
}.asCompletableFuture()
|
||||
}
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal fun SuggestionsBuilder.applyAny(any: Any?) {
|
||||
when (any) {
|
||||
is Int -> suggest(any)
|
||||
is String -> suggest(any)
|
||||
else -> suggest(any.toString())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@PublishedApi
|
||||
internal fun SuggestionsBuilder.applyAnyWithTooltip(pair: Pair<Any?, Message>?) {
|
||||
if (pair == null) return
|
||||
val (any, message) = pair
|
||||
when (any) {
|
||||
is Int -> suggest(any, message)
|
||||
is String -> suggest(any, message)
|
||||
else -> suggest(any.toString(), message)
|
||||
}
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal fun SuggestionsBuilder.applyIterable(iterable: Iterable<Any?>?) =
|
||||
iterable?.forEach(::applyAny)
|
||||
|
||||
@PublishedApi
|
||||
internal fun SuggestionsBuilder.applyIterableWithTooltips(iterable: Iterable<Pair<Any?, Message>?>?) =
|
||||
iterable?.forEach(::applyAnyWithTooltip)
|
||||
|
||||
/**
|
||||
* Adds custom suspending suggestion logic for an argument.
|
||||
*
|
||||
* @param coroutineScope the [CoroutineScope] where the suggestions should be built in - an async scope by default
|
||||
*/
|
||||
@Deprecated(
|
||||
"The name 'simpleSuggests' has been superseded by 'suggestListSuspending'",
|
||||
ReplaceWith("suggestListSuspending(coroutineScope, suggestionBuilder)")
|
||||
)
|
||||
fun <S> RequiredArgumentBuilder<S, *>.simpleSuggests(
|
||||
coroutineScope: CoroutineScope = argumentCoroutineScope,
|
||||
suggestionBuilder: suspend (CommandContext<S>) -> Iterable<Any?>?
|
||||
) = suggestListSuspending(coroutineScope, suggestionBuilder)
|
@@ -1,4 +1,4 @@
|
||||
package net.axay.kspigot.commands
|
||||
package net.axay.kspigot.commands.internal
|
||||
|
||||
import com.mojang.brigadier.arguments.*
|
||||
|
@@ -0,0 +1,82 @@
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
package net.axay.kspigot.commands.internal
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder
|
||||
import net.axay.kspigot.annotations.NMS_1_17
|
||||
import net.axay.kspigot.annotations.NMS_General
|
||||
import net.axay.kspigot.event.listen
|
||||
import net.axay.kspigot.extensions.onlinePlayers
|
||||
import net.axay.kspigot.extensions.server
|
||||
import net.axay.kspigot.main.KSpigotMainInstance
|
||||
import net.axay.kspigot.utils.reflectField
|
||||
import net.minecraft.commands.CommandListenerWrapper
|
||||
import org.bukkit.event.player.PlayerJoinEvent
|
||||
|
||||
typealias ServerCommandSource = CommandListenerWrapper
|
||||
|
||||
/**
|
||||
* This class provides Brigardier support. It does that
|
||||
* by using reflection once. Additionally, this class is
|
||||
* using some obfuscated functions.
|
||||
*/
|
||||
object BrigardierSupport {
|
||||
@PublishedApi
|
||||
internal val commands = LinkedHashSet<LiteralArgumentBuilder<CommandListenerWrapper>>()
|
||||
|
||||
internal var executedDefaultRegistration = false
|
||||
private set
|
||||
|
||||
init {
|
||||
listen<PlayerJoinEvent> { event ->
|
||||
val player = event.player
|
||||
val permAttachment = player.addAttachment(KSpigotMainInstance)
|
||||
commands.forEach {
|
||||
permAttachment.setPermission("minecraft.command.${it.literal}", true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The command manager is used to hold the command dispatcher,
|
||||
* and to manage and dispatch the brigardier commands for
|
||||
* all players on the server.
|
||||
*/
|
||||
@Suppress("HasPlatformType") // do not refer non-lazily to the type in this class
|
||||
@NMS_General
|
||||
val commandManager by lazy {
|
||||
(server as org.bukkit.craftbukkit.v1_17_R1.CraftServer).server.vanillaCommandDispatcher
|
||||
}
|
||||
|
||||
/**
|
||||
* The command dispatcher is used to register brigardier commands.
|
||||
*/
|
||||
@NMS_1_17
|
||||
val commandDispatcher by lazy {
|
||||
// g = the command dispatcher
|
||||
commandManager.reflectField<CommandDispatcher<CommandListenerWrapper>>("g")
|
||||
}
|
||||
|
||||
@NMS_General
|
||||
internal fun registerAll() {
|
||||
executedDefaultRegistration = true
|
||||
|
||||
// TODO unregister commands which are now missing due to a possible reload
|
||||
if (commands.isNotEmpty()) {
|
||||
commands.forEach {
|
||||
commandDispatcher.register(it)
|
||||
}
|
||||
if (onlinePlayers.isNotEmpty())
|
||||
updateCommandTree()
|
||||
}
|
||||
}
|
||||
|
||||
@NMS_General
|
||||
fun updateCommandTree() {
|
||||
onlinePlayers.forEach {
|
||||
// send the command tree
|
||||
commandManager.a((it as org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer).handle)
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
package net.axay.kspigot.main
|
||||
|
||||
import net.axay.kspigot.commands.internal.BrigardierSupport
|
||||
import net.axay.kspigot.extensions.bukkit.warn
|
||||
import net.axay.kspigot.extensions.console
|
||||
import net.axay.kspigot.gui.GUIHolder
|
||||
@@ -64,6 +65,8 @@ abstract class KSpigot : JavaPlugin() {
|
||||
|
||||
final override fun onEnable() {
|
||||
startup()
|
||||
|
||||
BrigardierSupport.registerAll()
|
||||
}
|
||||
|
||||
final override fun onDisable() {
|
||||
|
Reference in New Issue
Block a user