diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt index 5582cb536..2dcd4d407 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt @@ -90,19 +90,24 @@ internal object EventListenerManger { } // inline: NO extra Continuation +@Suppress("UNCHECKED_CAST") internal suspend inline fun Subscribable.broadcastInternal() { if (EventDisabled) return callAndRemoveIfRequired(this::class.listeners()) - this::class.supertypes.forEach { superType -> - val superListeners = - @Suppress("UNCHECKED_CAST") - (superType.classifier as? KClass)?.listeners() ?: return // return if super type is not Subscribable + var supertypes = this::class.supertypes + while (true) { + val superSubscribableType = supertypes.firstOrNull { + it.classifier as? KClass != null + } - callAndRemoveIfRequired(superListeners) + superSubscribableType?.let { + callAndRemoveIfRequired((it.classifier as KClass).listeners()) + } + + supertypes = (superSubscribableType?.classifier as? KClass<*>)?.supertypes ?: return } - return } private suspend inline fun E.callAndRemoveIfRequired(listeners: EventListeners) { diff --git a/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/event/EventTests.kt b/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/event/EventTests.kt index c9a486961..44b4bf1b3 100644 --- a/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/event/EventTests.kt +++ b/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/event/EventTests.kt @@ -1,5 +1,7 @@ package net.mamoe.mirai.event +import kotlinx.coroutines.CompletableJob +import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.runBlocking import net.mamoe.mirai.test.shouldBeEqualTo import kotlin.system.exitProcess @@ -16,28 +18,61 @@ class EventTests { runBlocking { val subscriber = subscribeAlways { triggered = true - println("Triggered") } TestEvent().broadcast().triggered shouldBeEqualTo true subscriber.complete() - println("finished") } } @Test fun testSubscribeGlobalScope() { runBlocking { - TestEvent().broadcast().triggered shouldBeEqualTo true - println("finished") - } + GlobalScope.subscribeAlways { + triggered = true + } + TestEvent().broadcast().triggered shouldBeEqualTo true + } + } + + + open class ParentEvent : Subscribable { + var triggered = false + } + + open class ChildEvent : ParentEvent() + + open class ChildChildEvent : ChildEvent() + + @Test + fun `broadcast Child to Parent`() { + runBlocking { + val job: CompletableJob + job = subscribeAlways { + triggered = true + } + ChildEvent().broadcast().triggered shouldBeEqualTo true + job.complete() + } + } + + @Test + fun `broadcast ChildChild to Parent`() { + runBlocking { + val job: CompletableJob + job = subscribeAlways { + triggered = true + } + ChildChildEvent().broadcast().triggered shouldBeEqualTo true + job.complete() + } } companion object { @JvmStatic fun main(args: Array) { - EventTests().testSubscribeGlobalScope() + EventTests().`broadcast ChildChild to Parent`() exitProcess(0) } }