async-moderation
Listens to PlayerChatEvent (an IAsyncEvent), runs a fake 200ms moderation
check off-thread, and on flagged messages bumps a warnings counter on the
world thread + cancels the event so it never reaches other players.
What it shows
eventRegistry.registerAsyncGlobal(PlayerChatEvent::class.java) { future -> … }— the global overload.registerAsynconly matchesIAsyncEvent<Void>, andPlayerChatEventisn'tVoid-keyed; the wrong overload compiles silently and never fires.scope.future { … }fromkotlinx-coroutines-jdk8— bridgesCompletableFuture↔ coroutines withoutrunBlocking.withContext(AsyncDispatchers.HytaleIO) { … }— for the simulated HTTP call.- Conditional
modify<T>(...)+event.isCancelled = true— the canonical shape for any moderation/filter handler.
Build
./gradlew shadowJar
# → build/libs/async-moderation.jar
Run
- Drop the JAR in
mods/, wireModerationStatsBinding.componentType()to your registered component. - Type a message containing
badword,spam, orscamin chat. - The message is suppressed; the sender's
ModerationStats.warningsincrements on the world thread.
The example uses a private CoroutineScope to make the supervisor
relationship explicit. In a real plugin, pluginScope(this) is fine and
flows through Async.shutdown() cleanly.