package me.eternal.purrfect.core.event import me.eternal.purrfect.core.ModContext import java.util.concurrent.ConcurrentHashMap import kotlin.reflect.KClass abstract class Event { lateinit var context: ModContext var canceled = false } interface IListener { fun handle(event: T) } class EventBus( val context: ModContext ) { private val subscribers = ConcurrentHashMap, MutableMap>>() fun subscribe(event: KClass, listener: IListener, priority: Int? = null) { synchronized(subscribers) { if (!subscribers.containsKey(event)) { subscribers[event] = sortedMapOf() } val lastSubscriber = subscribers[event]?.keys?.lastOrNull() ?: 0 subscribers[event]?.put(priority ?: (lastSubscriber + 1), listener) } } fun subscribe(event: KClass, priority: Int? = null, listener: (T) -> Unit) = subscribe(event, { true }, priority, listener) fun subscribe(event: KClass, filter: (T) -> Boolean, priority: Int? = null, listener: (T) -> Unit): () -> Unit { val obj = object : IListener { override fun handle(event: T) { if (!filter(event)) return runCatching { listener(event) }.onFailure { context.log.error("Error while handling event ${event::class.simpleName}", it) } } } subscribe(event, obj, priority) return { unsubscribe(event, obj) } } fun unsubscribe(event: KClass, listener: IListener) { synchronized(subscribers) { subscribers[event]?.values?.remove(listener) } } fun post(event: T, afterBlock: T.() -> Unit = {}): T? { if (!subscribers.containsKey(event::class)) { return null } event.context = context subscribers[event::class]?.toSortedMap()?.forEach { (_, listener) -> @Suppress("UNCHECKED_CAST") runCatching { (listener as IListener).handle(event) }.onFailure { t -> context.log.error("Error while handling event ${event::class.simpleName} by ${listener::class.simpleName}", t) } } afterBlock(event) return event } fun clear() { subscribers.clear() } }