Skip to content

GrimAnticheat/Grim-Example-API-Plugin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Grim Example API Plugin

Reference Bukkit/Paper plugin for ac.grim.grimac:GrimAPI:1.3.2.1.

This project shows the current event-channel API, the cross-platform GrimPlugin owner pattern, and the deprecated listener paths kept for older plugins that are migrating forward.

Building

./gradlew build

The jar is written to:

build/libs/Grim-Example-API-Plugin-1.0.0.jar

The project uses Java 17 and compiles against paper-api:1.20.4-R0.1-SNAPSHOT. The example only uses stable JavaPlugin and logging APIs, so the built jar is not tied to one Paper runtime version.

Installing

Put the jar in plugins/ next to GrimAC and restart the server:

plugins/
├── GrimAC-<version>.jar
└── Grim-Example-API-Plugin-1.0.0.jar

plugin.yml declares depend: [GrimAC], so this plugin enables after Grim has created the public API and event bus.

Modern Event API

Resolve Grim once, then subscribe through typed channels:

GrimAbstractAPI api = GrimAPIProvider.get();
EventBus bus = api.getEventBus();
GrimPlugin grim = api.getGrimPlugin(this);

bus.get(GrimTransactionSendEvent.class).onTransactionSend(grim, (user, id, ts) -> {
    getLogger().info("tx-send " + id + " for " + user.getName());
});

bus.get(FlagEvent.class).onFlag(grim, (user, check, verbose, cancelled) -> {
    if (shouldSuppress(user, check)) return true;
    return cancelled;
});

Cancellable handlers return the next cancelled state. Return the incoming cancelled value when you only want to observe.

Cross-Platform Shape

Do not manually construct BasicGrimPlugin for normal plugins. Pass the native owner object to api.getGrimPlugin(...) and let Grim resolve it.

Platform Owner object
Bukkit / Spigot / Paper JavaPlugin / Bukkit Plugin, usually this
Fabric ModInitializer, ModContainer, or the mod id string
Shared module A Class<?> from your plugin/mod

That lets you keep Grim-facing code in a shared class:

public final class GrimHooks {
    public static void register(Object owner) {
        GrimAbstractAPI api = GrimAPIProvider.get();
        GrimPlugin grim = api.getGrimPlugin(owner);
        EventBus bus = api.getEventBus();

        bus.get(FlagEvent.class).onFlag(grim, (user, check, verbose, cancelled) -> {
            grim.getLogger().info(user.getName() + " flagged " + check.getCheckName());
            return cancelled;
        });
    }
}

Bukkit/Paper:

public final class MyPlugin extends JavaPlugin {
    @Override
    public void onEnable() {
        GrimHooks.register(this);
    }
}

Fabric:

public final class MyMod implements ModInitializer {
    @Override
    public void onInitialize() {
        GrimHooks.register(this);
    }
}

Event Families

Subscribe to concrete channels when you need all fields. Subscribe to abstract channels when one handler should observe a whole family:

GrimCheckEvent.Channel checks =
        (GrimCheckEvent.Channel) bus.get(GrimCheckEvent.class);
checks.onCheck(grim, (user, check, cancelled) -> cancelled);

GrimVerboseCheckEvent.Channel verboseChecks =
        (GrimVerboseCheckEvent.Channel) bus.get(GrimVerboseCheckEvent.class);
verboseChecks.onVerboseCheck(grim, (user, check, verbose, cancelled) -> cancelled);

GrimSetbackEvent.Channel setbacks =
        (GrimSetbackEvent.Channel) bus.get(GrimSetbackEvent.class);
setbacks.onAnySetback(grim, (user, ts) ->
        getLogger().info("setback " + user.getName()));

GrimEvent.Channel allEvents = (GrimEvent.Channel) bus.get(GrimEvent.class);
allEvents.onAnyEvent(grim, (eventClass, cancelled) ->
        getLogger().fine(eventClass.getSimpleName()));

GrimPlayerSetbackEvent includes the teleport id and target position. GrimVehicleSetbackEvent includes the vehicle target position. GrimSetbackEvent bridges both when you only need the semantic setback signal.

Priority

Handlers run in ascending priority order. Lower priority runs first; higher priority runs later and gets the final say on cancellation.

bus.get(FlagEvent.class)
    .onFlag(grim, handler, 100, false);

ignoreCancelled = false means the handler is skipped after an earlier handler cancels the event. ignoreCancelled = true means it still runs and receives the current cancelled state.

This is the Bukkit priority direction. If you are migrating from pre-1.3 Grim, review any explicit priority numbers.

Legacy Paths

These still work for source compatibility, but new code should use typed channels:

@SuppressWarnings("deprecation")
bus.get(FlagEvent.class).onFlag((Object) this, (user, check, verbose, cancelled) -> {
    return cancelled;
});

bus.registerAnnotatedListeners(this, new Listener());

public final class Listener {
    @GrimEventHandler
    public void onJoin(GrimJoinEvent event) {
        // legacy reflective listener
    }
}

Use bus.unregisterAllListeners(this) or bus.unregisterAllListeners(grim) on disable if you want explicit cleanup. Grim also cleans up plugin-bound handlers as part of the plugin lifecycle.

Covered Events

This plugin demonstrates:

  • Transaction send and receive
  • Teleport
  • Player and vehicle setbacks
  • Join, quit, and reload
  • Flag, complete prediction, and command execute
  • Check, verbose-check, setback-family, and root event observers
  • Deprecated object-context and @GrimEventHandler listener paths

Storage, history, and verdict APIs are not demonstrated here. Those are separate extension points for datastore, dashboard, and verdict-engine integrations.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages