5fc3bda1c5
- player-load: load-on-join (PlayerReadyEvent → IO → modify). - async-moderation: IAsyncEvent → coroutine bridge for chat moderation. - periodic-leaderboard: pluginScope loop with parallel reads. - bounty-board: kitchen-sink demo exercising every v0.1 primitive.
37 lines
1.4 KiB
Markdown
37 lines
1.4 KiB
Markdown
# 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. `registerAsync` only matches `IAsyncEvent<Void>`, and
|
|
`PlayerChatEvent` isn't `Void`-keyed; the wrong overload compiles silently
|
|
and never fires.
|
|
- `scope.future { … }` from `kotlinx-coroutines-jdk8` — bridges
|
|
`CompletableFuture` ↔ coroutines without `runBlocking`.
|
|
- `withContext(AsyncDispatchers.HytaleIO) { … }` — for the simulated HTTP call.
|
|
- Conditional `modify<T>(...)` + `event.isCancelled = true` — the canonical
|
|
shape for any moderation/filter handler.
|
|
|
|
## Build
|
|
|
|
```bash
|
|
./gradlew shadowJar
|
|
# → build/libs/async-moderation.jar
|
|
```
|
|
|
|
## Run
|
|
|
|
1. Drop the JAR in `mods/`, wire `ModerationStatsBinding.componentType()` to
|
|
your registered component.
|
|
2. Type a message containing `badword`, `spam`, or `scam` in chat.
|
|
3. The message is suppressed; the sender's `ModerationStats.warnings`
|
|
increments 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.
|