Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,22 @@ class PhraseArgument(name: String) : StringArgument(name, StringType.PHRASE) {
it == ' '
}

setSuggestionOffset(greedyContext.phraseInput.length)
setSuggestionOffset(0)
if (greedyContext.phraseInput.isNotEmpty()) {
var tot = 0
for ((i, word) in greedyContext.arguments.withIndex()) {
if ((greedyContext.arguments.lastIndex == i && !greedyContext.input.endsWith(' ')) || word.isEmpty()) break
tot += word.length + 1
addSuggestionOffset(word.length + 1)
}
}

val suggestions: MutableList<Suggestion> = mutableListOf()
val word = words[amountOfSpaces] ?: return@addSuggestion emptyList()
for (stellarSuggestion in word.suggestions)
for (suggestion in stellarSuggestion.get(greedyContext)) suggestions.add(Suggestion.create(suggestion.text, suggestion.tooltip))
for (suggestion in stellarSuggestion.get(greedyContext)) {
suggestions.add(Suggestion.create(suggestion.text, suggestion.tooltip))
}
suggestions
}
}
Expand All @@ -55,7 +66,7 @@ class PhraseArgument(name: String) : StringArgument(name, StringType.PHRASE) {
* Creates a [WordArgument] at the [index], that you can configure with [init]. Only works in Kotlin.
* @return The modified [PhraseArgument] instance.
*/
inline fun addWordArgument(index: Int, init: WordArgument.() -> Unit = {}): PhraseArgument {
inline fun addWordArgument(index: Int, init: WordArgument.() -> Unit = {}): PhraseArgument {
val word = WordArgument()
word.init()
words[index] = word
Expand Down Expand Up @@ -228,10 +239,11 @@ class PhraseArgument(name: String) : StringArgument(name, StringType.PHRASE) {
val input = context.input.removePrefix("/")
val words = input.split(' ').toMutableList()

val totalOtherArguments = context.args.size - 1
for (i in (0..totalOtherArguments)) words.removeFirst()
val totalOtherArguments = if (this.name in context.args.keys) context.args.size - 1 else context.args.size
words.removeFirst() // to remove the base command like /[give]
for (i in (0 until totalOtherArguments)) words.removeFirst()

return PhraseCommandContext(context, words, context.sender, input.substring(input.indexOf(' ')), input)
return PhraseCommandContext(context, words, context.sender, words.joinToString(" "), input)
}

}
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
org.gradle.jvmargs=-Xmx4G

group=com.undefined
version=1.1.3
version=1.2.0-SNAPSHOT
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ fun <T> AbstractStellarCommand<*>.listArgument(
converter: suspend CommandContext<CommandSender>.(T) -> String? = { it.toString() },
scope: CoroutineScope = StellarConfig.scope,
block: ListArgument<T, String>.() -> Unit = {},
): ListArgument<T, String> = addArgument(ListArgument(StringArgument(name, StringType.WORD), {
): ListArgument<T, String> = addArgument(ListArgument(StringArgument(name, StringType.WORD), { input ->
scope.future {
list().mapNotNull {
val convertedText = converter(it).takeIf { suggestion -> suggestion?.isNotBlank() == true }
Expand All @@ -249,7 +249,7 @@ fun <T, R> AbstractStellarCommand<*>.listArgument(
converter: suspend CommandContext<CommandSender>.(T) -> String? = { it.toString() },
scope: CoroutineScope = StellarConfig.scope,
block: ListArgument<T, R>.() -> Unit = {},
): ListArgument<T, R> = addArgument(ListArgument(type, {
): ListArgument<T, R> = addArgument(ListArgument(type, { input ->
scope.future {
list.mapNotNull {
val convertedText = converter(it).takeIf { suggestion -> suggestion?.isNotBlank() == true }
Expand All @@ -270,12 +270,12 @@ fun <T, R> AbstractStellarCommand<*>.listArgument(
*/
fun <T, R> AbstractStellarCommand<*>.listArgument(
type: ParameterArgument<*, R>,
list: suspend CommandContext<CommandSender>.() -> List<T>,
list: suspend CommandContext<CommandSender>.() -> Iterable<T>,
parse: CommandSender.(R) -> T,
converter: suspend CommandContext<CommandSender>.(T) -> String? = { it.toString() },
scope: CoroutineScope = StellarConfig.scope,
block: ListArgument<T, R>.() -> Unit = {},
): ListArgument<T, R> = addArgument(ListArgument(type, {
): ListArgument<T, R> = addArgument(ListArgument(type, { input ->
scope.future {
list().mapNotNull {
val convertedText = converter(it).takeIf { suggestion -> suggestion?.isNotBlank() == true }
Expand All @@ -300,7 +300,7 @@ fun <T> AbstractStellarCommand<*>.advancedListArgument(
converter: suspend CommandContext<CommandSender>.(T) -> Suggestion? = { Suggestion.withText(it.toString()) },
scope: CoroutineScope = StellarConfig.scope,
block: ListArgument<T, String>.() -> Unit = {},
): ListArgument<T, String> = addArgument(ListArgument(StringArgument(name, StringType.WORD), {
): ListArgument<T, String> = addArgument(ListArgument(StringArgument(name, StringType.WORD), { input ->
scope.future {
list.mapNotNull {
converter(it).takeIf { suggestion -> suggestion?.text?.isNotBlank() == true }
Expand All @@ -324,7 +324,7 @@ fun <T> AbstractStellarCommand<*>.advancedListArgument(
converter: suspend CommandContext<CommandSender>.(T) -> Suggestion? = { Suggestion.withText(it.toString()) },
scope: CoroutineScope = StellarConfig.scope,
block: ListArgument<T, String>.() -> Unit = {},
): ListArgument<T, String> = addArgument(ListArgument(StringArgument(name, StringType.WORD), {
): ListArgument<T, String> = addArgument(ListArgument(StringArgument(name, StringType.WORD), { input ->
scope.future {
list().mapNotNull {
converter(it).takeIf { suggestion -> suggestion?.text?.isNotBlank() == true }
Expand All @@ -349,7 +349,7 @@ fun <T, R> AbstractStellarCommand<*>.advancedListArgument(
converter: suspend CommandContext<CommandSender>.(T) -> Suggestion? = { Suggestion.withText(it.toString()) },
scope: CoroutineScope = StellarConfig.scope,
block: ListArgument<T, R>.() -> Unit = {},
): ListArgument<T, R> = addArgument(ListArgument(type, {
): ListArgument<T, R> = addArgument(ListArgument(type, { input ->
scope.future {
list.mapNotNull {
converter(it).takeIf { suggestion -> suggestion?.text?.isNotBlank() == true }
Expand All @@ -374,7 +374,7 @@ fun <T, R> AbstractStellarCommand<*>.advancedListArgument(
converter: suspend CommandContext<CommandSender>.(T) -> Suggestion? = { Suggestion.withText(it.toString()) },
scope: CoroutineScope = StellarConfig.scope,
block: ListArgument<T, R>.() -> Unit = {},
): ListArgument<T, R> = addArgument(ListArgument(type, {
): ListArgument<T, R> = addArgument(ListArgument(type, { input ->
scope.future {
list().mapNotNull {
converter(it).takeIf { suggestion -> suggestion?.text?.isNotBlank() == true }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,19 @@ inline fun <reified C : CommandSender> AbstractStellarCommand<*>.execution(
}

/**
* Adds an async execution to the command with the use of [CompletableFuture].
* Adds an async execution to the command using [StellarConfig.asyncScope].
*
* @param C The type of CommandSender.
* @param execution The execution block.
*/
inline fun <reified C : CommandSender> AbstractStellarCommand<*>.asyncExecution(noinline execution: CommandContext<C>.() -> Unit) = addAsyncExecution(execution)
inline fun <reified C : CommandSender> AbstractStellarCommand<*>.asyncExecution(
scope: CoroutineScope = StellarConfig.asyncScope,
noinline execution: suspend CommandContext<C>.() -> Unit,
): AbstractStellarCommand<*> = addAsyncExecution<C> {
scope.launch {
execution()
}
}

/**
* Adds a runnable to the command.
Expand All @@ -56,22 +63,28 @@ inline fun <reified C : CommandSender> AbstractStellarCommand<*>.runnable(
}

/**
* Adds an async runnable to the command with the use of [CompletableFuture].
* Adds an async runnable to the command using [StellarConfig.asyncScope].
*
* @param C The type of CommandSender.
* @param alwaysApplicable Whether it should always run or only when an execution is already present for the last argument.
* @param execution The execution block.
*/
inline fun <reified C : CommandSender> AbstractStellarCommand<*>.asyncRunnable(
alwaysApplicable: Boolean = false,
noinline execution: CommandContext<C>.() -> Boolean,
): AbstractStellarCommand<*> = addAsyncRunnable(alwaysApplicable, execution)
scope: CoroutineScope = StellarConfig.asyncScope,
noinline execution: suspend CommandContext<C>.() -> Unit,
): AbstractStellarCommand<*> = addAsyncRunnable<C>(alwaysApplicable) {
scope.launch {
execution()
}
true
}

/**
* Adds a failure execution to the command to be displayed when the command fails.
*
* @param C The type of CommandSender.
* @param scope The [CoroutineScope] used to create
* @param scope The [CoroutineScope] used to run the [execution] block (default: [StellarConfig.scope]).
* @param execution The execution block.
* @return The modified command object.
*/
Expand All @@ -87,8 +100,10 @@ inline fun <reified C : CommandSender> AbstractStellarCommand<*>.failureExecutio
/**
* Adds a requirement that must be met for the command to be available to the player.
*
* NOTE: the [requirement] block blocks the current thread.
*
* @param C The type of CommandSender.
* @param scope The [CoroutineScope] used to create
* @param scope The [CoroutineScope] used to run the [requirement] block (default: [StellarConfig.scope]).
* @param requirement The condition that must be met.
* @return The modified command object.
*/
Expand Down Expand Up @@ -132,10 +147,10 @@ fun ParameterArgument<*, *>.suggests(vararg suggestions: Suggestion) = addSugges
fun ParameterArgument<*, *>.suggests(title: String, tooltip: String? = null) = addSuggestion(title, tooltip)

/**
* Adds a function that returns a list of [Suggestion] on top of the current suggestions. Only works in Kotlin.
* Adds a function that returns a list of [Suggestion] on top of the current suggestions.
*
* @param C The type of CommandSender.
* @param scope The [CoroutineScope] used to create
* @param scope The [CoroutineScope] used to run the [suggestion] block (default: [StellarConfig.scope]).
* @return The modified [ParameterArgument].
*/
inline fun <reified C : CommandSender> ParameterArgument<*, *>.suggests(
Expand All @@ -145,4 +160,20 @@ inline fun <reified C : CommandSender> ParameterArgument<*, *>.suggests(
scope.future {
suggestion(input)
}
}

/**
* Adds a function that returns a list of [Suggestion] on top of the current suggestions.
*
* @param C The type of CommandSender.
* @param scope The [CoroutineScope] used to run the [suggestion] block (default: [StellarConfig.asyncScope]).
* @return The modified [ParameterArgument].
*/
inline fun <reified C : CommandSender> ParameterArgument<*, *>.asyncSuggests(
scope: CoroutineScope = StellarConfig.asyncScope,
noinline suggestion: suspend CommandContext<C>.(input: String) -> List<Suggestion>,
) = addFutureSuggestion<C> { input ->
scope.future {
suggestion(input)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,39 @@ import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
object KotlinStellarConfig {

var _scope: CoroutineScope? = null
val scope: CoroutineScope
private var _scope: CoroutineScope? = null
var scope: CoroutineScope
get() = _scope ?: error("Scope has not been set!")
set(value) {
_scope = value
}


private var _asyncScope: CoroutineScope? = null
var asyncScope: CoroutineScope
get() = _asyncScope ?: _scope ?: error("Neither the async scope or the scope has been set!")
set(value) {
_asyncScope = value
}

}

fun StellarConfig.setScope(scope: CoroutineScope): StellarConfig = apply {
KotlinStellarConfig._scope = scope
KotlinStellarConfig.scope = scope
}

fun StellarConfig.setAsyncScope(scope: CoroutineScope): StellarConfig = apply {
KotlinStellarConfig.asyncScope = scope
}

/**
* [CoroutineScope] used for any executions or blocks that have to be run in suspend.
*/
val StellarConfig.scope: CoroutineScope
get() = KotlinStellarConfig.scope

/**
* [CoroutineScope] used for any executions or blocks that are run in async that have to be run in suspend.
*/
val StellarConfig.asyncScope: CoroutineScope
get() = KotlinStellarConfig.asyncScope
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ object MojangAdapter {
.appendNewline()
.append(Component.text("... $message").color(NamedTextColor.GRAY))
.append(Component.translatable("command.context.here"))
MessageComponentSerializer.message().serialize(component).also { println("message: $it") }
MessageComponentSerializer.message().serialize(component)
}

fun getStellarCommandContext(context: BrigadierCommandContext<Any>): CommandContext<CommandSender> {
Expand Down
1 change: 0 additions & 1 deletion server/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ tasks {
}
shadowJar {
archiveFileName = "server.jar"
outputs.upToDateWhen { false }
}
compileKotlin {
compilerOptions.jvmTarget = JvmTarget.JVM_21
Expand Down
21 changes: 21 additions & 0 deletions server/src/main/kotlin/com/undefined/stellar/BaseCommand.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.undefined.stellar

import com.undefined.stellar.kotlin.KotlinBaseStellarCommand
import com.undefined.stellar.kotlin.literalArgument
import com.undefined.stellar.kotlin.runnable
import org.bukkit.entity.Player

object BaseCommand : KotlinBaseStellarCommand("base") {
override fun setup(): StellarCommand = kotlinCommand {
literalArgument("give") {
runnable<Player> {
val flags = getOrNull<String>("flags") ?: "FUCK"
sender.sendMessage(flags)
true
}
addPhraseArgument("flags")
.addWordSuggestions(0, "-v", "-s")
.addWordSuggestions(1, "-v", "-s")
}
}
}
5 changes: 2 additions & 3 deletions server/src/main/kotlin/com/undefined/stellar/Main.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
package com.undefined.stellar

import com.undefined.stellar.data.argument.CommandContext
import com.undefined.stellar.data.execution.StellarExecution
import com.undefined.stellar.kotlin.setScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import org.bukkit.entity.Player
import org.bukkit.plugin.java.JavaPlugin
import org.bukkit.profile.PlayerProfile

class Main : JavaPlugin() {

Expand All @@ -27,6 +24,8 @@ class Main : JavaPlugin() {
sender.sendMessage("<gray>Your balance: 100 euros")
}
.register()

BaseCommand.register(this)
}

}
24 changes: 15 additions & 9 deletions spigot/api/src/main/kotlin/com/undefined/stellar/NMSManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -156,18 +156,24 @@ object NMSManager {

private fun handleSuggestions(argument: AbstractStellarCommand<*>, argumentBuilder: ArgumentBuilder<Any, *>) {
if (argument !is ParameterArgument<*, *> || argument._suggestions.isEmpty() || argumentBuilder !is RequiredArgumentBuilder<Any, *>) return
argumentBuilder.suggests { context, builder ->
val stellarContext = MojangAdapter.getStellarCommandContext(context)
val range = StringRange.between(builder.start + argument.suggestionOffset, builder.input.length)

argumentBuilder.suggests { context, rawBuilder ->
CompletableFuture.supplyAsync {
val stellarContext = MojangAdapter.getStellarCommandContext(context)
val suggestions: MutableList<Suggestion> = mutableListOf()
for (suggestion in argument._suggestions) suggestions.addAll(suggestion.get(stellarContext, builder.remaining).get())
for (suggestion in argument._suggestions)
suggestions.addAll(suggestion.get(stellarContext, rawBuilder.remaining).get())

Suggestions(range, suggestions.map { suggestion ->
if (suggestion.tooltip == null || suggestion.tooltip!!.isBlank()) BrigadierSuggestion(range, suggestion.text)
else BrigadierSuggestion(range, suggestion.text) { suggestion.tooltip }
})
val builder = if (argument.suggestionOffset != 0) rawBuilder.createOffset(rawBuilder.start + argument.suggestionOffset) else rawBuilder

for (suggestion in suggestions) {
if (suggestion.text.startsWith(rawBuilder.remaining.substringAfterLast(' '), true))
if (suggestion.tooltip == null)
builder.suggest(suggestion.text)
else
builder.suggest(suggestion.text) { suggestion.tooltip }
}

builder.build()
}
}
}
Expand Down