Skip to content

feat(core): add SurfEventBus for cross-plugin events#320

Draft
Copilot wants to merge 1 commit intoversion/26.1from
copilot/add-surf-event-bus
Draft

feat(core): add SurfEventBus for cross-plugin events#320
Copilot wants to merge 1 commit intoversion/26.1from
copilot/add-surf-event-bus

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 23, 2026

Introduces a central, platform-independent SurfEventBus so surf-* plugins (surf-playtime, surf-clan, …) can define and fire their own events and listen to others' events without taking a direct dependency on the firing plugin.

Core API (surf-api-core, dev.slne.surf.api.core.event)

  • SurfEvent parent + SurfSyncEvent / SurfAsyncEvent base classes and SurfCancellableEvent mixin (with isCancelled / cancel()).
  • SurfEventPriority enum (LOWESTMONITOR) and @SurfEventHandler(priority, ignoreCancelled) annotation.
  • SurfEventBus interface with companion object : SurfEventBus by requiredService(), plus registerListeners(vararg), unregisterListeners(vararg), and inline on<T> { … } / onAsync<T> { … } DSL helpers that return a token usable for unregistration.

Invoker infrastructure (dev.slne.surf.api.core.event.invoker, @InternalInvokerApi)

  • Java SurfSyncEventInvoker and SurfAsyncEventInvoker functional interfaces.
  • Hidden-class templates (SurfSyncEventInvokerTemplate, SurfAsyncEventInvokerTemplate) that reuse the existing InvokerFactory / HiddenInvokerUtil (sync via loadClassData, async via loadClassDataWithAutoSuspend, branching on DATA.isSuspend()).

Implementation (surf-api-core-server)

  • SurfEventBusImpl registered via @AutoService(SurfEventBus::class) and guarded with checkInstantiationByServiceLoader().
  • Validates handler signatures at registration: exactly one SurfEvent-subtype parameter; suspend rejected for SurfSyncEvent handlers.
  • Storage: ConcurrentHashMap<Class, ConcurrentSkipListMap<Priority, CopyOnWriteArrayList<RegisteredHandler>>>. Dispatch matches every registered type assignable from the concrete event class, sorts the union by priority, honours ignoreCancelled, and isolates handler exceptions via Flogger.
  • Async dispatch awaits each handler sequentially through suspendCoroutineUninterceptedOrReturn, supporting both suspend and non-suspend handlers transparently.

Sample events (surf-api-paper, dev.slne.surf.api.paper.event.surf)

  • AbstractSurfPlayerEvent(playerUuid) async base.
  • PlayerAfkStateChangeEvent(playerUuid, fromState, toState) implementing SurfCancellableEvent.

Usage

class AfkListener {
    @SurfEventHandler(priority = SurfEventPriority.HIGH, ignoreCancelled = true)
    suspend fun onAfk(event: PlayerAfkStateChangeEvent) { /**/ }
}

SurfEventBus.registerListeners(AfkListener())

val token = SurfEventBus.onAsync<PlayerAfkStateChangeEvent> { event -> /**/ }
SurfEventBus.callAsync(PlayerAfkStateChangeEvent(uuid, false, true))
SurfEventBus.unregisterListeners(token)

Kotlin ABI dumps for surf-api-core and surf-api-paper are regenerated. The Bukkit/Velocity event systems are untouched and coexist with this bus.

…ple Paper events

Agent-Logs-Url: https://github.com/SLNE-Development/surf-api/sessions/5ea8a361-4ecf-4c77-bff6-5f750e2f54b9

Co-authored-by: twisti-dev <76837088+twisti-dev@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants