Commit e4e526ca authored by Him188's avatar Him188

Support object implementations of Event

parent 23273718
...@@ -12,11 +12,14 @@ ...@@ -12,11 +12,14 @@
package net.mamoe.mirai.event package net.mamoe.mirai.event
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import net.mamoe.mirai.JavaFriendlyAPI import net.mamoe.mirai.JavaFriendlyAPI
import net.mamoe.mirai.event.internal.broadcastInternal import net.mamoe.mirai.event.internal.broadcastInternal
import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.utils.MiraiExperimentalAPI
import net.mamoe.mirai.utils.SinceMirai import net.mamoe.mirai.utils.SinceMirai
import net.mamoe.mirai.utils.internal.runBlocking import net.mamoe.mirai.utils.internal.runBlocking
import kotlin.jvm.JvmField
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
import kotlin.jvm.JvmSynthetic import kotlin.jvm.JvmSynthetic
import kotlin.jvm.Volatile import kotlin.jvm.Volatile
...@@ -28,6 +31,9 @@ import kotlin.jvm.Volatile ...@@ -28,6 +31,9 @@ import kotlin.jvm.Volatile
* *
* 所有 [Event] 都应继承 [AbstractEvent] 而不要直接实现 [Event]. 否则将无法广播也无法监听. * 所有 [Event] 都应继承 [AbstractEvent] 而不要直接实现 [Event]. 否则将无法广播也无法监听.
* *
* ### 广播
* 广播事件的唯一方式为 [broadcast].
*
* @see subscribeAlways * @see subscribeAlways
* @see subscribeOnce * @see subscribeOnce
* *
...@@ -53,7 +59,9 @@ interface Event { ...@@ -53,7 +59,9 @@ interface Event {
* *
* 当事件被 [拦截][Event.intercept] 后, 优先级较低 (靠右) 的监听器将不会被调用. * 当事件被 [拦截][Event.intercept] 后, 优先级较低 (靠右) 的监听器将不会被调用.
* *
* @see [Listener.EventPriority] 查看优先级相关信息 * 优先级为 [Listener.EventPriority.MONITOR] 的监听器不应该调用这个函数.
*
* @see Listener.EventPriority 查看优先级相关信息
*/ */
@SinceMirai("1.0.0") @SinceMirai("1.0.0")
fun intercept() fun intercept()
...@@ -81,8 +89,13 @@ abstract class AbstractEvent : Event { ...@@ -81,8 +89,13 @@ abstract class AbstractEvent : Event {
final override val DoNotImplementThisClassButExtendAbstractEvent: Nothing final override val DoNotImplementThisClassButExtendAbstractEvent: Nothing
get() = throw Error("Shouldn't be reached") get() = throw Error("Shouldn't be reached")
/** 限制一个事件实例不能并行广播. (适用于 object 广播的情况) */
@JvmField
internal val broadCastLock = Mutex()
@JvmField
@Volatile @Volatile
private var _intercepted = false internal var _intercepted = false
@Volatile @Volatile
private var _cancelled = false private var _cancelled = false
...@@ -142,14 +155,24 @@ interface CancellableEvent : Event { ...@@ -142,14 +155,24 @@ interface CancellableEvent : Event {
/** /**
* 广播一个事件的唯一途径. * 广播一个事件的唯一途径.
* @see __broadcastJava *
* 当事件被实现为 Kotlin `object` 时, 同一时刻只能有一个 [广播][broadcast] 存在. 较晚执行的 [广播][broadcast] 将会挂起协程并等待之前的广播任务结束.
*
* @see __broadcastJava Java 使用
*/ */
@JvmSynthetic @JvmSynthetic
suspend fun <E : Event> E.broadcast(): E = apply { suspend fun <E : Event> E.broadcast(): E = apply {
check(this is AbstractEvent) {
"Events must extend AbstractEvent"
}
if (this is BroadcastControllable && !this.shouldBroadcast) { if (this is BroadcastControllable && !this.shouldBroadcast) {
return@apply return@apply
} }
this@broadcast.broadcastInternal() // inline, no extra cost this.broadCastLock.withLock {
this._intercepted = false
this.broadcastInternal() // inline, no extra cost
}
} }
/** /**
...@@ -164,7 +187,7 @@ fun <E : Event> E.__broadcastJava(): E = apply { ...@@ -164,7 +187,7 @@ fun <E : Event> E.__broadcastJava(): E = apply {
if (this is BroadcastControllable && !this.shouldBroadcast) { if (this is BroadcastControllable && !this.shouldBroadcast) {
return@apply return@apply
} }
runBlocking { this@__broadcastJava.broadcastInternal() } runBlocking { this@__broadcastJava.broadcast() }
} }
/** /**
......
...@@ -126,13 +126,13 @@ internal expect class MiraiAtomicBoolean(initial: Boolean) { ...@@ -126,13 +126,13 @@ internal expect class MiraiAtomicBoolean(initial: Boolean) {
// inline: NO extra Continuation // inline: NO extra Continuation
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
internal suspend inline fun Event.broadcastInternal() { internal suspend inline fun AbstractEvent.broadcastInternal() {
if (EventDisabled) return if (EventDisabled) return
callAndRemoveIfRequired(this@broadcastInternal as? AbstractEvent ?: error("Events must extends AbstractEvent")) callAndRemoveIfRequired(this@broadcastInternal)
} }
@Suppress("DuplicatedCode") @Suppress("DuplicatedCode")
internal suspend fun <E : AbstractEvent> callAndRemoveIfRequired( internal suspend inline fun <E : AbstractEvent> callAndRemoveIfRequired(
event: E event: E
) { ) {
for (p in Listener.EventPriority.valuesExceptMonitor) { for (p in Listener.EventPriority.valuesExceptMonitor) {
......
...@@ -28,9 +28,10 @@ import kotlin.reflect.jvm.kotlinFunction ...@@ -28,9 +28,10 @@ import kotlin.reflect.jvm.kotlinFunction
* *
* ### Kotlin 函数 * ### Kotlin 函数
* Kotlin 函数要求: * Kotlin 函数要求:
* - 接收者和函数参数: 所标注的 Kotlin 函数必须至少拥有一个接收者或一个函数参数, 或二者都具有. 接收者和函数参数的类型必须相同 (如果二者都有) * - 接收者 (英 receiver) 和函数参数: 所标注的 Kotlin 函数必须至少拥有一个接收者或一个函数参数, 或二者都具有. 接收者和函数参数的类型必须相同 (如果二者都存在)
* 接收者或函数参数的类型都必须为 [Event] 或其子类. * 接收者或函数参数的类型都必须为 [Event] 或其子类.
* - 返回值: 为 [Unit] 或不指定返回值时将注册为 [CoroutineScope.subscribeAlways], 为 [ListeningStatus] 时将注册为 [CoroutineScope.subscribe] * - 返回值: 为 [Unit] 或不指定返回值时将注册为 [CoroutineScope.subscribeAlways], 为 [ListeningStatus] 时将注册为 [CoroutineScope.subscribe].
* 任何其他类型的返回值将会在注册时抛出异常.
* *
* 所有 Kotlin 非 `suspend` 的函数都将会在 [Dispatchers.IO] 中调用 * 所有 Kotlin 非 `suspend` 的函数都将会在 [Dispatchers.IO] 中调用
* *
...@@ -118,8 +119,8 @@ import kotlin.reflect.jvm.kotlinFunction ...@@ -118,8 +119,8 @@ import kotlin.reflect.jvm.kotlinFunction
annotation class EventHandler( annotation class EventHandler(
/** /**
* 监听器优先级 * 监听器优先级
* @see Listener.EventPriority * @see Listener.EventPriority 查看优先级相关信息
* @see Event.intercept * @see Event.intercept 拦截事件
*/ */
val priority: Listener.EventPriority = EventPriority.NORMAL, val priority: Listener.EventPriority = EventPriority.NORMAL,
/** /**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment