Nova AntiCheat logo

Nova AntiCheat

Developer API

Public Bukkit API

Build server integrations on Nova’s normalized state.

Nova exposes a stable Java API for plugins running on the same Bukkit server. Read player and client state, inspect registered checks, query violations, use prediction context, control explicit exemptions, and integrate Nova Guard into competitive modes.

Reference reviewed on 12 August 2026.

Access

Accessing the Nova API

Nova owns the API instance. Never construct NovaAPI or GuardAPI yourself. Use one of these supported access patterns after Nova has enabled.

Direct plugin access

NovaAntiCheat nova = NovaAntiCheat.getInstance();
NovaAPI api = nova != null ? nova.getApi() : null;

Static helper

NovaAPI api = NovaAPI.get();

Bukkit services manager

RegisteredServiceProvider<NovaAPI> provider =
    Bukkit.getServicesManager().getRegistration(NovaAPI.class);
NovaAPI api = provider != null ? provider.getProvider() : null;

A hard integration can declare depend: [NovaAntiCheat]. A plugin that can operate without Nova may use softdepend: [NovaAntiCheat], look up the Bukkit service, and handle a missing provider. No separate public API artifact or Maven coordinate is promised currently.

Always handle startup and shutdown.

Check api != null and api.isRunning() before relying on Nova. Cache neither internal Nova objects nor Guard runtime objects.

Core

Runtime and integration

  • isRunning() reports whether the Nova plugin instance is enabled.
  • getVersion() returns Nova’s current version.
  • reloadConfig() reloads Nova configuration; safeReload() runs Nova’s full safe reload flow.
  • getDebugMode(player) returns that player’s current Nova debug mode.

Reload operations mutate live plugin state and must run on the Bukkit main thread.

Player state

Player and client state

These methods expose Nova’s server-side view without exposing prediction internals.

  • isPlayerTracked(player) reports whether Nova has created prediction state for the player.
  • isPredictionReady(player) additionally requires that prediction is usable and movement is not currently blocked by a correction.
  • isPredictionGrounded(player) — Nova’s current grounded result.
  • isJavaPlayer(player), isBedrockPlayer(player), isEaglerPlayer(player), and getEdition(player).
  • getClientBrand(player), getClientVersion(player), and getProtocolVersion(player). An unknown protocol returns -1.
  • getPing(player), getAveragePing(player), and getOnlinePlayerCount().

Edition booleans are mutually exclusive. Eagler sessions may still use compatible Java-family detectors when Eagler checking is enabled, so use getEdition(player) when the exact client family matters.

if (api.isPlayerTracked(player) && api.isPredictionReady(player)) {
    String edition = api.getEdition(player);
    String version = api.getClientVersion(player);
    int ping = api.getPing(player);
}

Check catalog

Checks and metadata

Prefer qualified check IDs such as java:Speed-A. Qualification prevents a Java, Bedrock, prediction, or Guard check with a similar display name from being confused with another check.

  • getRegisteredChecks() returns registered qualified IDs.
  • getChecks() and getCheck("java:Speed-A") return CheckDetails.
  • isCheckEnabled(id), isCheckRegistered(id), getCheckCategory(id), and getCheckDisplayName(id).

CheckDetails provides getQualifiedId(), getId(), getDisplayName(), getCategory(), getEdition(), getClientSupport(), isExperimental(), isEnabled(), and getConfigPath().

for (NovaAPI.CheckDetails check : api.getChecks()) {
    getLogger().info(check.getQualifiedId()
        + " | " + check.getCategory()
        + " | " + check.getClientSupport());
}

Violations

Read and reset violation state

  • getViolations(player, "java:Speed-A") reads one check’s current VL.
  • getTotalViolations(player) reads the player’s aggregate tracked VL.
  • hasFlaggedRecently(player, "java:Speed-A", 20) checks a recent tick window.
  • resetViolations(player, "java:Speed-A") and resetAllViolations(player) mutate tracked violation state.
Tick windows use Minecraft ticks.

A value of 20 means approximately one second at normal server tick rate, not 20 milliseconds.

Responses

Exemptions and setbacks

These calls change Nova behavior and should be reserved for deliberate server logic.

  • hasBypass(player, "java:Speed-A") checks the configured bypass permission.
  • grantTemporaryExemption(player, 40), grantPermanentExemption(player), and revokeTemporaryExemption(player).
  • isTemporarilyExempt(player) and getTemporaryExemptionTicksRemaining(player).
  • isSetbacked(player), getSetbackTicksRemaining(player), and forceSetback(player).

Do not grant an exemption merely because a player uses Nova Guard. Guard verification is additional evidence and never a trust bonus.

Context

Movement and context helpers

  • isInLiquid(player), isInWeb(player), isClimbing(player), isOnIce(player), and isOnSlime(player).
  • hasRecentTeleport(player, 20), hasRecentVelocity(player, 20), and hasRecentDamage(player, 20).
  • hasRecentRodPull(player, 8), hasRecentWind(player, 20), and hasRecentSpearJab(player, 20).

All withinTicks arguments are Minecraft tick windows. These helpers reuse Nova’s normalized state instead of requiring an integration to reproduce environment tracking.

AntiESP

Visibility integration

  • isHiddenFrom(viewer, target) reports Nova’s current visibility decision.
  • refreshViewerVisibility(viewer) refreshes one viewer.
  • refreshAllViewerVisibility() refreshes all viewers.
  • getAntiEspPerformanceStats() returns a concise diagnostic summary.

Nova Pro and Dev

Nova Guard API

Access Guard through api.getGuardApi() or nova.getGuardApi(). Nova also provides flat convenience methods for the common operations. Guard is available with Nova Pro and Dev entitlements. On an unavailable or non-Pro installation, the API returns conservative inactive results.

  • isGuardEnabled(), isGuardVerified(player), and getGuardStatus(player).
  • getGuardRequirement() returns the global policy; getGuardRequirementInfo(player) returns the effective player policy and safe label.
  • getGuardSessionExpiry(player) and isGuardRequired(player).
  • requireGuard(player, "Ranked Queue") and clearGuardRequirement(player).
  • getGuardSessions() returns privacy-safe snapshots of current local-backend paired sessions.

Player and UUID overloads exist for state, expiry, requirement, require, and clear operations. A per-player requirement is removed when the player disconnects. Clearing it only removes the API-created requirement: a global REQUIRED policy cannot be cleared or bypassed by another plugin.

Guard requirements are access policy.

A Guard requirement failure is session/access policy, not a cheating violation. Verified Guard does not lower VL, reduce confidence, disable checks, weaken normal Nova, or make setbacks less strict.

Stable state model

Guard statuses and results

GuardStatusMeaning
DISABLEDGuard is inactive or unavailable for this installation/player.
UNPAIREDNo current paired Guard launch is available.
PAIRINGPairing or connection establishment is in progress.
VERIFIEDGuard is active and eligible as an additional verified source.
PAUSEDVerification is temporarily unavailable; do not treat this as a cheat result.
DISCONNECTEDThe Guard connection or Minecraft session was lost.
EXPIREDThe current Guard launch session expired.

GuardRequirement is DISABLED, OPTIONAL, or REQUIRED.

GuardRequirementInfo provides getRequirement(), getReason(), isGlobal(), isRequired(), and getDisplayName().

Successful GuardRequirementResult values are APPLIED, UPDATED, and ALREADY_REQUIRED. Failure values are GUARD_UNAVAILABLE, PLAYER_OFFLINE, PLAYER_NOT_APPLICABLE, PLAYER_BYPASSED, INVALID_REASON, and NOT_SERVER_THREAD. Check result.isSuccessful() rather than assuming every call applied.

GuardSessionInfo is a privacy-safe session snapshot with getPlayerId(), getPlayerName(), getStatus(), getRequirement(), and getSessionExpiry().

Events

Guard events

All public Guard events are synchronous Bukkit events fired on the Bukkit server thread.

  • GuardStatusChangeEvent exposes getPreviousStatus() and getNewStatus().
  • GuardVerifiedEvent fires when active, correlation-eligible verification is gained.
  • GuardVerificationLostEvent fires when a previously verified player loses active verification and exposes getNewStatus().

Common getters are getPlayer(), getPlayerId(), getRequirement(), getReason(), and getSessionExpiry(). The optional reason is diagnostic context; do not display it directly to players or branch on exact strings.

@EventHandler
public void onGuardStatusChange(GuardStatusChangeEvent event) {
    switch (event.getNewStatus()) {
        case VERIFIED -> updateCompetitiveAccess(event.getPlayer(), true);
        case PAUSED, DISCONNECTED, EXPIRED ->
            updateCompetitiveAccess(event.getPlayer(), false);
        default -> { }
    }
}

Example

Require Guard for a ranked queue

Keep the server globally OPTIONAL, require Guard only when a player enters competitive matchmaking, and wait for verification before admitting them.

private GuardAPI guardApi() {
    NovaAPI api = NovaAPI.get();
    return api != null ? api.getGuardApi() : null;
}

public void requestRankedAccess(Player player) {
    GuardAPI guard = guardApi();
    if (guard == null || !guard.isGuardEnabled()) {
        denyRanked(player, "Nova Guard is unavailable.");
        return;
    }
    if (guard.isGuardVerified(player)) {
        enterRankedMode(player);
        return;
    }

    GuardRequirementResult result =
        guard.requireGuard(player, "Ranked Queue");
    if (!result.isSuccessful()) {
        denyRanked(player, "Guard could not be required: " + result);
    }
}

@EventHandler
public void onGuardVerified(GuardVerifiedEvent event) {
    if (rankedQueue.contains(event.getPlayerId())) {
        enterRankedMode(event.getPlayer());
    }
}

@EventHandler
public void onGuardLost(GuardVerificationLostEvent event) {
    if (rankedMatch.contains(event.getPlayerId())) {
        pauseCompetitiveAccess(event.getPlayer(), event.getNewStatus());
    }
}

public void leaveRanked(Player player) {
    GuardAPI guard = guardApi();
    if (guard != null) {
        guard.clearGuardRequirement(player);
    }
}

The player receives Nova’s normal Guard grace and pairing flow. Grace expiry follows the Guard access policy without cheat VL. Normal Nova checks remain fully active for verified and unverified players.

Optional integration

PlaceholderAPI

PlaceholderAPI is an optional soft dependency. Nova works normally without it.

PlaceholderExample
%nova_version%Current Nova version
%nova_status%Active
%nova_tps%19.98
%nova_client_edition%Java, Bedrock, or Eagler
%nova_client_version%1.21.11
%nova_checks_enabled%true
%nova_ping%42
%nova_average_ping%47
%nova_guard_status%VERIFIED
%nova_guard_verified%true
%nova_guard_requirement%OPTIONAL, REQUIRED, or a safe per-player label
%nova_guard_session_remaining%21h 42m

When Guard is unavailable, Guard placeholders return safe inactive values such as DISABLED, false, and N/A.

Contract

Threading, lifecycle and safety

  • Call Guard requirement mutations, reloadConfig(), and safeReload() on the Bukkit main thread.
  • Guard events already run synchronously on the Bukkit server thread.
  • Use concise, nonblank per-player requirement labels because they may appear in administrator views and placeholders.
  • Prefer query methods for display logic. Treat resets, exemptions, setbacks, reloads, and requirements as intentional mutations.
  • Handle disabled, unavailable, offline, unknown, and empty optional results rather than assuming every player has complete state.
The public API is deliberately privacy-safe.

It does not expose session keys, raw input, telemetry, IP addresses, authentication secrets, transport state, or Guard protocol internals.

The supported public boundary is me.cerial.NovaAntiCheat.api, including api.guard and api.guard.event. Packages under Nova’s utils tree, NovaGuardProtocol, and NovaGuardVelocity are internal and may change without API compatibility guarantees.