feat: SurfEventBus — central annotation-driven cross-plugin event bus#319
Draft
Copilot wants to merge 2 commits intoversion/26.1from
Draft
feat: SurfEventBus — central annotation-driven cross-plugin event bus#319Copilot wants to merge 2 commits intoversion/26.1from
Copilot wants to merge 2 commits intoversion/26.1from
Conversation
- Add SurfEvent, SurfAsyncEvent, SurfSyncEvent, SurfCancellableEvent base types - Add SurfEventHandler annotation and SurfEventPriority enum - Add SurfEventBus interface with annotation-based and lambda-based registration - Add event-bus-extensions.kt with on<T>/onAsync<T>/registerListeners(vararg) helpers - Add SurfSyncEventInvoker/SurfAsyncEventInvoker interfaces and hidden class templates - Add SurfEventInvokerFactory and SurfEventBusImpl (AutoService) in core-server - Add AbstractSurfPlayerEvent and PlayerAfkStateChangeEvent example events in paper - Update ABI dumps for surf-api-core and surf-api-paper Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: twisti-dev <76837088+twisti-dev@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Add central SurfEventBus for surf-plugins
feat: SurfEventBus — central annotation-driven cross-plugin event bus
Apr 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Plugins like
surf-advancementscurrently must take direct dependencies on every plugin whose events they care about. This adds a platform-independent event bus tosurf-api-coreso any plugin can fire and listen to events without coupling.Event hierarchy
SurfEvent— common markerSurfAsyncEvent/SurfSyncEvent— base classes; async allowssuspendlisteners, sync validates against them at registration timeSurfCancellableEvent— interface withisCancelled/cancel()API (
surf-api-core)@SurfEventHandler(priority, ignoreCancelled)annotation;SurfEventPriorityenum (LOWEST→MONITOR), Bukkit-independentSurfEventBusinterface with companion delegation viarequiredService():registerListeners(Any)— scans for@SurfEventHandlermethods, validates suspend/param constraintscallAsync(SurfAsyncEvent)/callSync(SurfSyncEvent)— dispatches in priority orderregisterHandler/registerAsyncHandler— lambda-based alternativeon<T>,onAsync<T>,registerListeners(vararg)DSL extensionsSurfSyncEventInvoker/SurfAsyncEventInvokerfunctional interfaces + hidden-class templates using the existingInvokerFactory/HiddenInvokerUtilinfrastructureImplementation (
surf-api-core-server)SurfEventBusImpl—@AutoService(SurfEventBus::class),ConcurrentHashMap<EventClass, ConcurrentHashMap<Priority, CopyOnWriteArrayList<HandlerEntry>>>; sealedHandlerEntrycovers both invoker-based and lambda-based handlersContinuation-passing invoker into coroutine context viasuspendCoroutineUninterceptedOrReturnExample events (
surf-api-paper)AbstractSurfPlayerEventandPlayerAfkStateChangeEventas concrete migration examples (previously lived insurf-playtime).Usage
Original prompt
Ziel
Implementiere einen zentralen SurfEventBus in
surf-api, der es allen surf-Plugins (surf-playtime, surf-clan, surf-advancements, etc.) ermöglicht, ihre eigenen Events zu definieren und zu feuern – und anderen Plugins zu erlauben, darauf zu lauschen, ohne eine direkte Dependency auf das feuernde Plugin zu haben.Der Event Bus soll wie die bestehenden Redis/RabbitMQ-Listener per Annotation über der Methode funktionieren und die bestehende InvokerAPI (
InvokerFactory,HiddenInvokerUtil,InvokerClassData) für Performance nutzen.Anforderungen
1. Event-Typen (zwei Varianten)
SurfAsyncEvent(Marker-Interface / Basisklasse)suspendseinkotlinx.coroutines)call()zurückkommtSurfSyncEvent(Marker-Interface / Basisklasse)suspendsein (wird zur Registrierungszeit validiert und geworfen)Beide sollten ein gemeinsames Eltern-Interface
SurfEventhaben.Beide sollten cancellable sein können, über ein
SurfCancellableEvent-Interface (mitisCancelledProperty undcancel()-Methode).2. Annotation
@SurfEventHandlerEventPrioritysoll ein eigenes Enum sein (nicht Bukkit-abhängig), da der Event Bus plattformunabhängig insurf-api-coreleben soll:3.
SurfEventBus(API-Interface insurf-api-core)registerListeners(listener)scannt alle Methoden des Objekts nach@SurfEventHandlerSurfSyncEvent-Handlern, dass die Methode nicht suspend istSurfAsyncEvent-Handlern, dass die Methode genau einen Parameter hat (den Event-Typ)InvokerFactory+HiddenInvokerUtilfür performante Dispatch-Implementierung4. Invoker-Infrastruktur (analog zu Redis/RabbitMQ)
Erstelle analog zur bestehenden Invoker-Infrastruktur:
Invoker-Interfaces (Java):
Template-Klassen analog zu anderen Invoker-Templates im Projekt (für hidden class bytecode).
SurfEventInvokerFactory– nutztInvokerFactory<SurfSyncEventInvoker>bzw.InvokerFactory<SurfAsyncEventInvoker>.5. Implementierung
SurfEventBusImpl(insurf-api-core-server)@AutoService(SurfEventBus::class)ConcurrentHashMap<Class<out SurfEvent>, ConcurrentSkipListMap<SurfEventPriority, List<RegisteredHandler>>>gruppiert nach Event-Klasse und PriorityRegisteredHandlerenthält: Listener-Instanz, Invoker (entweder sync oder async), Priority, ignoreCancelledcoroutineScopesequenziell mitsuspend6. Erweiterungen / DSL (in
surf-api-core)7. Beispiel-Events in
surf-api-paperErstelle ein Package
dev.slne.surf.api.paper.event.surfmit folgenden Beispiel-Events: