[英]Kotlin coroutines in Minecraft spigot plugin
在文档中它说协程比线程轻,所以我想使用 kotlin 协程而不是 BukkitRunnable。
//Defined as class field
private val scope = coroutineScope(Dispatchers.Default)
//In class method
scope.launch {/* wait some seconds and then change blockdata */}
从 Dispatchers.Default 线程调用 setBlockData 会引发错误,因为 spigot API 不是线程安全的,并且您不能从主线程以外的线程调用 API 的东西。
java.lang.IllegalStateException: Asynchronous block remove!
我在想更改块数据相当于 Minecraft 中的 android UI 更改,这意味着协程需要运行/注入到主线程中。 所以在 Dispatchers.Main 中运行我的协程是有意义的。 但是,我找不到使用 Dispatchers.Main 并将其设置为主线程而不会得到非法状态异常的方法
我希望我的逻辑在这里是正确的
如果您想要一个能够将挂起代码与主线程桥接的简单方法(可以从主线程获取一些信息并在您的协程上使用),您可以使用此方法:
suspend fun <T> suspendSync(plugin: Plugin, task: () -> T): T = withTimeout(10000L) {
// Context: The current coroutine context
suspendCancellableCoroutine { cont ->
// Context: The current coroutine context
Bukkit.getScheduler().runTask(plugin) {
// Context: Bukkit MAIN thread
// runCatching is used to forward any exception that may occur here back to
// our coroutine, keeping the exceptions transparency of Kotlin coroutines
runCatching(task).fold({ cont.resume(it) }, cont::resumeWithException)
}
}
}
我已经评论了代码的每个部分执行的上下文,以便您可以可视化上下文切换。 suspendCancellableCoroutine
是一种获取所有协程在后台使用的continuation
object 的方法,因此我们可以在主线程执行我们的任务后手动恢复它。
外部块withTimeout
用于如果主线程没有在 10 秒内完成我们的任务,我们的协程放弃而不是永远挂起。
而且使用也很简单:
val plugin = // comes from somewhere
// example coroutine scope
CoroutineScope(Dispatchers.Default).launch {
// doing stuff async
// oh no, I need some data from the main thread!
val block = suspendSync(plugin) {
// this code runs on the MAIN thread
Bukkit.getWorld("blah").getBlockAt(0, 0, 0)
}
// back to async here, do stuff with block (just don't MODIFY it async, use more suspendSync if needed)
}
如果您有任何问题或事情我可以改进此答案,请不要害怕让我知道。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.