Skip to content

Commit b1e9992

Browse files
Boy00000ffz
andauthored
feat: Improve Brigadier-Command logic (#78)
* fix: handle permissions for commands by default * chore(commands): Clean up how default command permissions work, allow unsetting permissions from a command (by setting permission = null) feat(commands): By default, check whether sender has and parent command with .* for permissions * refactor(commands): Pass arguments through executes block feat(commands): Support trailing default arguments * chore: Fix playerExecutes overloads * fix: Take nativeType from CustomArgumentType instead of double wrapping it * fix: playerExecutes not providing pre-cast player * fix: ensure blank-permissions require no permission * feat: Named arguments fix: Allow case with all command arguments default * fix: Don't wrap types, avoid suggests block when no custom suggestions are passed so command names get shown * feat: add target to playerExecutes by default * fix: Correctly send argument exception text to executor refactor: Clean up some command context classes * fix(commands): Catch all errors in executes block, avoids a server crash * chore: add kotlinx.io dependency * fix: toIdo() called on existing IdoArgumentType incorrectly wraps command twice chore: Remove sample command in ido plugin class * fix: use FoodSurrogate instead of serializing FoodComponent due to usingConvertsTo & prefab-load-order --------- Co-authored-by: Danielle Voznyy <dan.voznyy@gmail.com>
1 parent 5089270 commit b1e9992

14 files changed

Lines changed: 417 additions & 129 deletions

File tree

gradle/libs.versions.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ kmongo = "5.1.0"
1717
kotest = "5.9.1"
1818
# @pin
1919
kotlin = "2.0.21"
20+
kotlinxIO = "0.5.4"
2021
ktor = "2.3.11"
2122
logback = "1.5.9"
2223
mccoroutine = "2.20.0"
@@ -64,6 +65,7 @@ kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref =
6465
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" }
6566
kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
6667
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" }
68+
kotlinx-io = { module = "org.jetbrains.kotlinx:kotlinx-io-core", version.ref = "kotlinxIO" }
6769
kotlinx-serialization-cbor = { module = "org.jetbrains.kotlinx:kotlinx-serialization-cbor", version.ref = "serialization" }
6870
kotlinx-serialization-hocon = { module = "org.jetbrains.kotlinx:kotlinx-serialization-hocon", version = "serialization" }
6971
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization" }
@@ -115,6 +117,7 @@ platform = [
115117
"kotlin-reflect",
116118
"kotlin-stdlib",
117119
"kotlinx-coroutines",
120+
"kotlinx-io",
118121
"kotlinx-serialization-cbor",
119122
"kotlinx-serialization-hocon",
120123
"kotlinx-serialization-json",
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package com.mineinabyss.idofront.commands.brigadier
2+
3+
import com.mineinabyss.idofront.commands.brigadier.context.IdoCommandContext
4+
import com.mojang.brigadier.arguments.ArgumentType
5+
6+
7+
inline fun <reified A: Any> IdoCommand.executes(
8+
a: ArgumentType<A>,
9+
crossinline run: IdoCommandContext.(A) -> Unit
10+
) {
11+
executesDefaulting(a) { (a) -> run(arg<A>(a)) }
12+
}
13+
14+
inline fun <reified A: Any, reified B: Any> IdoCommand.executes(
15+
a: ArgumentType<A>,
16+
b: ArgumentType<B>,
17+
crossinline run: IdoCommandContext.(A, B) -> Unit
18+
) {
19+
executesDefaulting(a, b) { (a, b) -> run(arg<A>(a), arg<B>(b)) }
20+
}
21+
22+
inline fun <reified A: Any, reified B: Any, reified C: Any> IdoCommand.executes(
23+
a: ArgumentType<A>,
24+
b: ArgumentType<B>,
25+
c: ArgumentType<C>,
26+
crossinline run: IdoCommandContext.(A, B, C) -> Unit
27+
) {
28+
executesDefaulting(a, b, c) { (a, b, c) -> run(arg<A>(a), arg<B>(b), arg<C>(c)) }
29+
}
30+
31+
inline fun <reified A: Any, reified B: Any, reified C: Any, reified D: Any> IdoCommand.executes(
32+
a: ArgumentType<A>,
33+
b: ArgumentType<B>,
34+
c: ArgumentType<C>,
35+
d: ArgumentType<D>,
36+
crossinline run: IdoCommandContext.(A, B, C, D) -> Unit
37+
) {
38+
executesDefaulting(a, b, c, d) { (a, b, c, d) -> run(arg<A>(a), arg<B>(b), arg<C>(c), arg<D>(d)) }
39+
}
40+
41+
inline fun <reified A: Any, reified B: Any, reified C: Any, reified D: Any, reified E: Any> IdoCommand.executes(
42+
a: ArgumentType<A>,
43+
b: ArgumentType<B>,
44+
c: ArgumentType<C>,
45+
d: ArgumentType<D>,
46+
e: ArgumentType<E>,
47+
crossinline run: IdoCommandContext.(A, B, C, D, E) -> Unit
48+
) {
49+
executesDefaulting(a, b, c, d, e) { (a, b, c, d, e) -> run(arg<A>(a), arg<B>(b), arg<C>(c), arg<D>(d), arg<E>(e)) }
50+
}
51+
52+
inline fun <reified A: Any, reified B: Any, reified C: Any, reified D: Any, reified E: Any, reified F: Any> IdoCommand.executes(
53+
a: ArgumentType<A>,
54+
b: ArgumentType<B>,
55+
c: ArgumentType<C>,
56+
d: ArgumentType<D>,
57+
e: ArgumentType<E>,
58+
f: ArgumentType<F>,
59+
crossinline run: IdoCommandContext.(A, B, C, D, E, F) -> Unit
60+
) {
61+
executesDefaulting(a, b, c, d, e, f) { run(arg<A>(it[0]), arg<B>(it[1]), arg<C>(it[2]), arg<D>(it[3]), arg<E>(it[4]), arg<F>(it[5])) }
62+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package com.mineinabyss.idofront.commands.brigadier
2+
3+
import com.mineinabyss.idofront.commands.brigadier.context.IdoPlayerCommandContext
4+
import com.mojang.brigadier.arguments.ArgumentType
5+
6+
7+
inline fun <reified A: Any> IdoCommand.playerExecutes(
8+
a: ArgumentType<A>,
9+
crossinline run: IdoPlayerCommandContext.(A) -> Unit
10+
) {
11+
playerExecutesDefaulting(a) { (a) -> run(arg<A>(a)) }
12+
}
13+
14+
inline fun <reified A: Any, reified B: Any> IdoCommand.playerExecutes(
15+
a: ArgumentType<A>,
16+
b: ArgumentType<B>,
17+
crossinline run: IdoPlayerCommandContext.(A, B) -> Unit
18+
) {
19+
playerExecutesDefaulting(a, b) { (a, b) -> run(arg<A>(a), arg<B>(b)) }
20+
}
21+
22+
inline fun <reified A: Any, reified B: Any, reified C: Any> IdoCommand.playerExecutes(
23+
a: ArgumentType<A>,
24+
b: ArgumentType<B>,
25+
c: ArgumentType<C>,
26+
crossinline run: IdoPlayerCommandContext.(A, B, C) -> Unit
27+
) {
28+
playerExecutesDefaulting(a, b, c) { (a, b, c) -> run(arg<A>(a), arg<B>(b), arg<C>(c)) }
29+
}
30+
31+
inline fun <reified A: Any, reified B: Any, reified C: Any, reified D: Any> IdoCommand.playerExecutes(
32+
a: ArgumentType<A>,
33+
b: ArgumentType<B>,
34+
c: ArgumentType<C>,
35+
d: ArgumentType<D>,
36+
crossinline run: IdoPlayerCommandContext.(A, B, C, D) -> Unit
37+
) {
38+
playerExecutesDefaulting(a, b, c, d) { (a, b, c, d) -> run(arg<A>(a), arg<B>(b), arg<C>(c), arg<D>(d)) }
39+
}
40+
41+
inline fun <reified A: Any, reified B: Any, reified C: Any, reified D: Any, reified E: Any> IdoCommand.playerExecutes(
42+
a: ArgumentType<A>,
43+
b: ArgumentType<B>,
44+
c: ArgumentType<C>,
45+
d: ArgumentType<D>,
46+
e: ArgumentType<E>,
47+
crossinline run: IdoPlayerCommandContext.(A, B, C, D, E) -> Unit
48+
) {
49+
playerExecutesDefaulting(a, b, c, d, e) { (a, b, c, d, e) -> run(arg<A>(a), arg<B>(b), arg<C>(c), arg<D>(d), arg<E>(e)) }
50+
}
51+
52+
inline fun <reified A: Any, reified B: Any, reified C: Any, reified D: Any, reified E: Any, reified F: Any> IdoCommand.playerExecutes(
53+
a: ArgumentType<A>,
54+
b: ArgumentType<B>,
55+
c: ArgumentType<C>,
56+
d: ArgumentType<D>,
57+
e: ArgumentType<E>,
58+
f: ArgumentType<F>,
59+
crossinline run: IdoPlayerCommandContext.(A, B, C, D, E, F) -> Unit
60+
) {
61+
playerExecutesDefaulting(a, b, c, d, e, f) { run(arg<A>(it[0]), arg<B>(it[1]), arg<C>(it[2]), arg<D>(it[3]), arg<E>(it[4]), arg<F>(it[5])) }
62+
}

idofront-commands/src/main/kotlin/com/mineinabyss/idofront/commands/brigadier/IdoArgument.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package com.mineinabyss.idofront.commands.brigadier
22

3+
import com.mineinabyss.idofront.commands.brigadier.context.IdoCommandContext
34
import kotlin.reflect.KProperty
45

56
class IdoArgument<T>(
67
val name: String,
8+
val resolve: ((IdoCommandContext, Any) -> T)? = null,
9+
val default: ((IdoCommandContext) -> T)? = null,
710
) {
811
operator fun getValue(thisRef: Any?, property: KProperty<*>): IdoArgument<T> {
912
return this
Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,68 @@
11
package com.mineinabyss.idofront.commands.brigadier
22

3+
import com.github.shynixn.mccoroutine.bukkit.asyncDispatcher
4+
import com.github.shynixn.mccoroutine.bukkit.scope
5+
import com.mineinabyss.idofront.commands.brigadier.context.IdoCommandContext
6+
import com.mineinabyss.idofront.commands.brigadier.context.IdoSuggestionsContext
7+
import com.mojang.brigadier.StringReader
38
import com.mojang.brigadier.arguments.ArgumentType
9+
import com.mojang.brigadier.context.CommandContext
10+
import com.mojang.brigadier.suggestion.SuggestionProvider
11+
import com.mojang.brigadier.suggestion.Suggestions
12+
import com.mojang.brigadier.suggestion.SuggestionsBuilder
13+
import io.papermc.paper.command.brigadier.CommandSourceStack
14+
import kotlinx.coroutines.future.future
15+
import org.bukkit.Bukkit
16+
import java.util.concurrent.CompletableFuture
417

5-
data class IdoArgumentBuilder<T>(
6-
val type: ArgumentType<out T>,
7-
val suggestions: (suspend IdoSuggestionsContext.() -> Unit)? = null,
8-
)
18+
data class IdoArgumentType<T>(
19+
val nativeType: ArgumentType<Any>,
20+
val name: String? = null,
21+
val resolve: ((IdoCommandContext, Any) -> T)? = null,
22+
val suggestions: ((CommandContext<Any>, SuggestionsBuilder) -> CompletableFuture<Suggestions>)? = null,
23+
val commandExamples: MutableCollection<String>,
24+
val default: (IdoCommandContext.() -> T)? = null,
25+
) : ArgumentType<T> {
26+
fun createType() = nativeType
27+
28+
override fun parse(reader: StringReader?) =
29+
error("IdoArgumentType should not be parsed directly, call createType() instead.")
30+
31+
inline fun suggests(crossinline suggestions: suspend IdoSuggestionsContext.() -> Unit): IdoArgumentType<T> =
32+
copy(
33+
suggestions = { context, builder ->
34+
val plugin = Bukkit.getPluginManager().getPlugin("Idofront")!!
35+
plugin.scope.future(plugin.asyncDispatcher) {
36+
suggestions(IdoSuggestionsContext(context as CommandContext<CommandSourceStack>, builder))
37+
builder.build()
38+
}
39+
}
40+
)
41+
42+
fun suggests(provider: SuggestionProvider<CommandSourceStack>): IdoArgumentType<T> = copy(
43+
suggestions = { context, suggestions ->
44+
provider.getSuggestions(
45+
context as CommandContext<CommandSourceStack>,
46+
suggestions
47+
)
48+
},
49+
)
50+
51+
fun default(default: IdoCommandContext.() -> T): IdoArgumentType<T> =
52+
copy(default = default)
53+
54+
inline fun <R> map(crossinline transform: IdoCommandContext.(T) -> R): IdoArgumentType<R> =
55+
IdoArgumentType(
56+
nativeType = nativeType,
57+
name = name,
58+
resolve = { context, value ->
59+
resolve
60+
?.let { transform(context, it(context, value)) }
61+
?: transform(context, value as T)
62+
},
63+
suggestions = suggestions,
64+
commandExamples = commandExamples,
65+
)
66+
67+
fun named(name: String) = copy(name = name)
68+
}

0 commit comments

Comments
 (0)