Turn scattered security alerts into actionable player incidents.
Sunshine Sentinel correlates GrimAC violations, SunshineCommandGuard blocked attempts and CoreProtect world activity into one explainable, per-player risk timeline — and turns HIGH risk activity into reviewable incidents. It is an investigation prioritization engine, not an anti-cheat and not a punishment system: it never bans, kicks or rolls back anything.
Requires JDK 21+ (compiles with the Java 21 toolchain).
gradlew.bat build
The distributable plugin jar is produced at build/libs/SunshineSentinel-0.1.0.jar.
- Drop the jar into
plugins/on a Paper 1.21.x server (Java 21). - Start the server. Sentinel auto-detects GrimAC, CoreProtect and SunshineCommandGuard.
- Run
/sentinel status— everything green means ready. - Optionally configure a Discord webhook in
plugins/SunshineSentinel/config.yml.
The plugin runs with any combination of integrations — including none — and stays idle until one becomes available. Only an unavailable SQLite database disables the plugin.
| Plugin | Role | API |
|---|---|---|
| GrimAC | Push-based flag collection via the 1.3+ typed event bus | ac.grim.grimac:GrimAPI (compileOnly, not shaded) |
| SunshineCommandGuard | Blocked command attempts (privacy / namespace probes) | Reflection-based event contract — requires SunshineCommandGuard 1.4.0+ |
| CoreProtect | Incident enrichment only — world activity snapshot at incident creation | Public API, never direct SQL |
SunshineCommandGuard must expose com.sunshine.commandguard.api.event.CommandGuardBlockedEvent
(non-cancellable, root command token only). Sentinel reports
INCOMPATIBLE — Detected: X.Y.Z, Required: 1.4.0+ in /sentinel status for older builds.
All mutable Sentinel state (risk windows, incident lifecycle) is owned by a single
SunshineSentinel-Worker thread. CoreProtect lookups run on a dedicated DB thread
and their results are marshaled back to the worker; Discord HTTP runs on its own
executor with delivery callbacks marshaled to the worker; all Bukkit API access
(GUI rendering, broadcasts) is scheduled to the server thread. Persistence
receives immutable incident snapshots in worker submission order.
Cancelled Grim flags are ignored by default (risk.grim.ignore-cancelled).
Command arguments are never stored — only the normalized root token, with
namespaces preserved deliberately: /plugins, /bukkit:plugins and
/minecraft:plugins are distinct evidence of command discovery.
Sentinel never modifies Grim's flag decisions.
/sentinel Incident GUI
/sentinel incidents Incident list
/sentinel player <name> Live player risk view
/sentinel incident <id> Incident detail (GUI or console text)
/sentinel ack|resolve|dismiss <id>
/sentinel status Health and diagnostics
/sentinel reload Validated config reload
/sentinel debug score <player> Explainable score breakdown
Permissions: sentinel.use, sentinel.view, sentinel.manage,
sentinel.notify, sentinel.reload, sentinel.status, sentinel.debug,
sentinel.ignore (players with this permission are not tracked).
Rolling 15-minute window per player; each signal contributes
base weight × decay × repetition × ping × TPS with explainable breakdown:
diversity (+6 for 3+ anti-cheat categories), cross-source (+10),
temporal clustering (+5), command enumeration burst (+8) and CoreProtect
contextual correlation (capped, never incident-triggering on its own).
Scores are 0–100 with LOW / MEDIUM / HIGH / CRITICAL bands; incidents are
created at 60, escalate to CRITICAL notifications once at 80, and merge into
an existing OPEN/ACKNOWLEDGED incident for 10 minutes.
SQLite (WAL) at plugins/SunshineSentinel/sentinel.db with a versioned
schema, single-writer threading, restart recovery of the risk window and
daily retention purges (events 7 days, closed incidents 30 days).
All database, HTTP and CoreProtect work happens off the server tick thread.