Skip to content
This repository was archived by the owner on Sep 15, 2025. It is now read-only.

Commit b471dc4

Browse files
committed
fix: ij coroutines not working as paper library, refactor: move axi modules to dependency handler
1 parent 17b9b56 commit b471dc4

File tree

24 files changed

+96
-62
lines changed

24 files changed

+96
-62
lines changed

core/src/main/kotlin/net/radstevee/axi/command/CloudCommandExecutionContext.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,18 @@ import kotlinx.coroutines.CoroutineScope
44
import org.bukkit.entity.Player
55
import org.incendo.cloud.context.CommandContext
66
import org.incendo.cloud.paper.util.sender.Source
7-
import kotlin.coroutines.AbstractCoroutineContextElement
87
import kotlin.coroutines.CoroutineContext
98

109
internal class CloudCommandExecutionContext(
1110
override val ctx: CommandContext<Source>,
1211
override var coroutineContext: CoroutineContext,
1312
scope: CoroutineScope,
14-
) : AbstractCoroutineContextElement(CloudCommandExecutionContext),
15-
CommandExecutionContext,
13+
) : CommandExecutionContext,
1614
CoroutineScope by scope {
1715
override val player: Player by lazy { ctx.player }
1816
override val source: Source by lazy { ctx.sender() }
1917

20-
companion object : CoroutineContext.Key<CloudCommandExecutionContext>
18+
companion object {
19+
val Holder: ThreadLocal<CloudCommandExecutionContext> = ThreadLocal()
20+
}
2121
}

core/src/main/kotlin/net/radstevee/axi/command/Command.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package net.radstevee.axi.command
22

33
import net.radstevee.axi.plugin.AxiPlugin
44
import net.radstevee.axi.plugin.AxiPluginHolder
5+
import org.jetbrains.annotations.ApiStatus
56

67
/** Represents a wrapped cloud command. */
78
public interface Command {
@@ -12,7 +13,8 @@ public interface Command {
1213
public val aliases: Set<String>
1314

1415
/** The permission required to use this command, defaults to `pluginName.command.commandName`. */
15-
public val permission: String
16+
@set:ApiStatus.Internal
17+
public var permission: String
1618

1719
/** The children of this command. */
1820
public val children: Set<Command>

core/src/main/kotlin/net/radstevee/axi/command/CommandArguments.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ public open class CommandArgument<T : Any>(
1616
public open val descriptor: ParserDescriptor<Source, T>,
1717
) {
1818
public open operator fun getValue(thisRef: Any?, property: KProperty<*>): T? {
19-
val coroutineContext = IntellijCoroutines.currentThreadCoroutineContext() ?: error("not in a coroutine")
20-
val ctx = coroutineContext[CloudCommandExecutionContext] ?: error("no execution context found")
19+
val ctx = CloudCommandExecutionContext.Holder.get() ?: error("thread local unset")
2120
return ctx.ctx.get<T>(id)
2221
}
2322
}
2423

2524
/**
2625
* An instance of a command argument that cannot be null, by either providing
26+
*
2727
* a) providing a default
2828
* b) using a required argument
2929
*/
@@ -40,8 +40,7 @@ public class NonNullableCommandArgument<T : Any>(
4040
return super.getValue(thisRef, property)!!
4141
}
4242

43-
val coroutineContext = IntellijCoroutines.currentThreadCoroutineContext() ?: error("not in a coroutine")
44-
val ctx = coroutineContext[CloudCommandExecutionContext] ?: error("no execution context found")
43+
val ctx = CloudCommandExecutionContext.Holder.get() ?: error("thread local unset")
4544
return ctx.ctx.getOrDefault<T>(id, default)
4645
}
4746
}

core/src/main/kotlin/net/radstevee/axi/command/CommandBuilder.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,21 @@ public class CommandBuilder(
7171
/** Adds a sub command. */
7272
public fun sub(name: String, aliases: Set<String> = setOf(), block: (@CommandBuilderDsl CommandBuilder).() -> Unit = {}) {
7373
val builder = CommandBuilder(name, plugin)
74+
builder.aliases(*aliases.toTypedArray())
7475
builder.permission("$permission.$name")
7576

7677
children.add(builder.apply(block).build())
7778
}
7879

80+
/** Adds a command with its permission as long as [useSubPermission] is set to true. */
81+
public fun sub(command: Command, useSubPermission: Boolean = true) {
82+
if (!useSubPermission) {
83+
command.permission = "$permission.${command.name}"
84+
}
85+
86+
children.add(command)
87+
}
88+
7989
/** Adds the given [aliases]. */
8090
public fun aliases(vararg aliases: String) {
8191
this.aliases += aliases

core/src/main/kotlin/net/radstevee/axi/command/CommandImpl.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ package net.radstevee.axi.command
44
public class CommandImpl(
55
override val name: String,
66
override val aliases: Set<String>,
7-
override val permission: String,
7+
override var permission: String,
88
override val children: Set<Command>,
99
override val args: Set<CommandArgument<*>>,
1010
override val asyncHandler: Boolean,

core/src/main/kotlin/net/radstevee/axi/command/CommandRegistration.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package net.radstevee.axi.command
22

3-
import kotlinx.coroutines.SupervisorJob
43
import kotlinx.coroutines.coroutineScope
5-
import kotlinx.coroutines.launch
64
import net.radstevee.axi.coroutines.AxiCoroutines.asyncContext
75
import net.radstevee.axi.coroutines.AxiCoroutines.coroutineScope
86
import net.radstevee.axi.coroutines.AxiCoroutines.syncContext
@@ -40,16 +38,18 @@ public fun Command.register(manager: CommandManager = AxiPluginHolder.plugin().c
4038
asyncContext
4139
} else {
4240
syncContext
43-
} + SupervisorJob()
41+
}
4442

4543
suspendingHandler(scope = coroutineScope, context = coroutineContext) { ctx ->
4644
coroutineScope {
4745
val executionContext = CloudCommandExecutionContext(ctx, coroutineContext, this)
48-
executionContext.coroutineContext += executionContext
49-
executionContext.launch(executionContext.coroutineContext) {
46+
CloudCommandExecutionContext.Holder.set(executionContext)
47+
try {
5048
with(command) {
5149
executionContext.execute()
5250
}
51+
} finally {
52+
CloudCommandExecutionContext.Holder.remove()
5353
}
5454
}
5555
}

docs/src/getting-started/quickstart.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ plugins {
4444
id("xyz.jpenilla.run-task") version "2.3.1"
4545
}
4646

47-
axi {
48-
modules("core")
47+
dependencies {
48+
axi.modules("core")
4949
}
5050
```
5151
:::
@@ -94,11 +94,11 @@ Now you're good to go!
9494
9595
If you need a dependency in your plugin, you can use paper's
9696
library loading feature by adding the dependency using the
97-
`axiDependency` function:
97+
`axi.runtime` function:
9898

9999
```kt
100100
dependencies {
101-
axiDependency("...")
101+
axi.runtime("...")
102102
}
103103
```
104104

@@ -114,8 +114,8 @@ plugins {
114114
id("xyz.jpenilla.run-task") version "2.3.1"
115115
}
116116
117-
axi {
118-
modules("core")
117+
dependencies {
118+
axi.modules("core")
119119
}
120120
121121
tasks.runServer {

example/build.gradle.kts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
1-
// Doing this here since the plugin is already
2-
// on the classpath
3-
apply(plugin = "org.jetbrains.kotlin.jvm")
4-
51
plugins {
62
id("net.radstevee.axi")
73
id("xyz.jpenilla.run-paper") version "2.3.1"
4+
kotlin("jvm")
85
}
96

107
group = "net.radstevee.axi.example"
118
version = "0.0.0"
129

13-
axi {
14-
modules("core", "ui")
10+
dependencies {
11+
axi.modules("core", "ui")
12+
}
13+
14+
kotlin {
15+
jvmToolchain(21)
16+
explicitApi()
1517
}
1618

1719
tasks {

example/src/main/kotlin/net/radstevee/axi/example/Commands.kt

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,20 @@ import net.radstevee.axi.ui.text.mm
1010
import org.incendo.cloud.parser.standard.IntegerParser.integerParser
1111
import org.incendo.cloud.parser.standard.StringParser.stringParser
1212

13+
private val TestTwoCommand = Command("two") {
14+
val num by arg("number", integerParser())
15+
16+
executor {
17+
ctx.sendMessage(text("number: $num"))
18+
}
19+
20+
sub("three") {
21+
executor {
22+
ctx.sendMessage(text("omg: $num"))
23+
}
24+
}
25+
}
26+
1327
@AutoRegistered
1428
val TestCommand: Command = Command("test") {
1529
executor {
@@ -24,19 +38,7 @@ val TestCommand: Command = Command("test") {
2438
}
2539
}
2640

27-
sub("two") {
28-
val num by arg("number", integerParser())
29-
30-
executor {
31-
ctx.sendMessage(text("number: $num"))
32-
}
33-
34-
sub("three") {
35-
executor {
36-
ctx.sendMessage(text("omg: $num"))
37-
}
38-
}
39-
}
41+
sub(TestTwoCommand)
4042
}
4143

4244
@AutoRegistered

example/src/main/kotlin/net/radstevee/axi/example/ConnectionListener.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import org.bukkit.event.EventHandler
1919
import org.bukkit.event.player.PlayerJoinEvent
2020
import kotlin.time.Duration.Companion.seconds
2121

22-
object ConnectionListener : SuspendingListener {
22+
public object ConnectionListener : SuspendingListener {
2323
@EventHandler
2424
private suspend fun on(event: PlayerJoinEvent) {
2525
val player = event.player

0 commit comments

Comments
 (0)