For developers
Hook your own plugins into Counter. Read violation levels, add exempts, and listen for flags, punishments and setbacks.
Getting started
There's no public Maven repo yet, so build against the Counter jar you download. Put it in a libs folder and add it as compile only.
dependencies {
compileOnly(files("libs/Counter.jar"))
}
With Maven, install the jar into your local repo once, then depend on it with provided scope.
mvn install:install-file -Dfile=Counter.jar -DgroupId=C -DartifactId=Counter -Dversion=1.3.0 -Dpackaging=jar
Then tell Bukkit to load Counter first.
softdepend: [Counter]
The API
Everything lives in C.counter.api. Counter registers CounterApi with the Bukkit services manager on startup.
CounterApi api = Bukkit.getServicesManager().load(CounterApi.class); if (api == null) return; double reach = api.vl(player, "ReachA");
CounterApi.get() returns the same instance, or null before Counter has started. Check names aren't case sensitive, so ReachA and reacha both work.
Methods
vl(Player, String check)Violation level on one checkvl(Player)Total violation levelvls(Player)Every check with a violation level, as a mapresetVl(Player)Clear all violation levelsresetVl(Player, String check)Clear one checkexempt(Player, long ms)Exempt from every check for a while. 0 or less removes itexempt(Player, String check, long ms)Exempt from one check, or a category like move, combat or playeractive(Player, String check)Whether a check is running for this player right nowenabled(String check)Whether a check is turned onchecks()The name of every checkclient(Player)The player's client, like Fabric or Lunar Clientbedrock(Player)Whether the player joined through Geyserping(Player)Ping in milliseconds, as Counter measures itfrozen(Player)Whether staff froze the playerEvents
All three events can be cancelled. They can fire off the main thread when a check runs on the packet thread, so don't touch the world from inside them. Hand that work to the scheduler instead.
FlagEvent
Fires before a flag counts. Cancel it and the flag is dropped, with no violation level and no alert.
getPlayer()The playergetCheck()Check name, like ReachAgetCategory()move, combat or playergetReason()The short reason shown in alertsgetInfo()The raw flag detailsgetVl()Violation level after this flaggetConfidence()0 to 1getTier()1 low, 2 medium, 3 high, 4 extremePunishEvent
Fires before a punishment runs. Cancel it to stop the punishment.
getPlayer()The playergetCheck()The check that reached its punish levelgetAction()The punishment about to rungetVl()Violation levelgetOffense()Which offense this is for the playerSetbackEvent
Fires before a player is set back. Cancel it to let the move through.
getPlayer()The playergetCheck()The check that caused itgetFrom()Where the player wasgetTo()Where they'll be sent back toExample
Log strong flags, and skip punishments for players in your own event mode.
public final class Hook implements Listener {
private final Set<UUID> eventMode = ConcurrentHashMap.newKeySet();
@EventHandler
public void onFlag(FlagEvent e) {
if (e.getTier() < 3) return;
Bukkit.getLogger().info(e.getPlayer().getName() + " " + e.getCheck() + ": " + e.getReason());
}
@EventHandler(ignoreCancelled = true)
public void onPunish(PunishEvent e) {
if (eventMode.contains(e.getPlayer().getUniqueId())) e.setCancelled(true);
}
}
Placeholders and permissions
If you only need numbers on a scoreboard or in chat, the PlaceholderAPI placeholders may be enough. To keep a player out of checks without code, give them counter.bypass, or narrow it with counter.bypass.combat, counter.bypass.fly or counter.bypass.flya.
Found a bug in the API? Run /counter dump and post the file on Discord or the SpigotMC page.