Polar Help

API Overview

Importing the API

To start using the Polar API, it must be included as a project dependency. Do not shade it. Add https://repo.polar.top/repository/polar/ to the dependency manager:

groupId = "top.polar" artifactId = "api" version = "2.0.0"

Example

repositories { maven { url = uri("https://repo.polar.top/repository/polar/") } } dependencies { compileOnly("top.polar:api:2.0.0") }
<repositories> <repository> <id>Polar</id> <url>https://repo.polar.top/repository/polar/</url> </repository> </repositories> <dependencies> <dependency> <groupId>top.polar</groupId> <artifactId>api</artifactId> <version>2.0.0</version> <scope>provided</scope> </dependency> </dependencies>

Basic usage

The PolarApiAccessor class is a convenient way to access the Polar API object. It provides a method to retrieve the PolarApi object supplied as a WeakReference.

try { var weakApi = top.polar.api.PolarApiAccessor.access(); } catch (PolarNotLoadedException __) { log.error("API access violation - Polar Anticheat is not loaded"); }

Important nuances regarding events

Polar API provides a flexible and robust event system to handle various server events. Events are represented by the PolarApiEvent class, and the API defines a hierarchy of event classes that extend from it.

Below is the inheritance hierarchy of the event classes, starting from PolarApiEvent and ending with the child classes:

java.lang.Object ↳ top.polar.api.event.PolarApiEvent ↳ top.polar.api.server.event.CloudConnectionEvent ↳ top.polar.api.server.event.CloudConnectedEvent ↳ top.polar.api.server.event.CloudDisconnectedEvent ↳ top.polar.api.server.event.CloudReconnectEvent ↳ top.polar.api.user.event.UserCancellableEvent ↳ top.polar.api.user.event.UserCancellableCheckEvent ↳ top.polar.api.user.event.DetectionEvent ↳ top.polar.api.user.event.MitigationEvent ↳ top.polar.api.user.event.OrdinaryKickEvent ↳ top.polar.api.user.event.PunishmentEvent

Polar class loading strategy

Polar classes are loaded asynchronously to Bukkit main thread. There may be a condition, at which, a plugin dependent on Polar was already loaded, but the PolarApiAccessor class has not been loaded yet.

The PolarLoader plugin includes a LoaderApi class, allowing to set up a preliminary listener, which is called the moment Polar is loaded completely.

Therefore, plugins utilizing the API need to depend on PolarLoader (through plugin.yml).

@Override public void onEnable() { top.polar.api.loader.LoaderApi.registerEnableCallback(() -> { // Ideally, this logic is implemented in an external class. // API access here // Listener registration here // ... etc }); }

Java class loading principle

Java ClassLoader will refuse to load any class that contains references to unknown classes. At Bukkit plugin loading stage, the API-using plugin may fail to load due to existing references to non-loaded classes in the main class.

At Polar pre-loading stage, the only accessible class is LoaderApi.

Other classes of the plugin, however, will be loaded on demand, since they are not called by Bukkit directly. We recommend to conduct all API calls in these classes and not in the main class directly. Hence, the callback listener should look like this:

top.polar.api.loader.LoaderApi.registerEnableCallback(YourPolarApiHook::init);

Possible race condition

Bukkit plugin manager, by default, first loads all plugins in an ordered sequence, then enables them in the same sequence.

PolarLoader is loaded in the standard Bukkit loading sequence, and Polar itself is loaded immediately after PolarLoader. However, Polar is not enabled in a Bukkit-specified sequence and is enabled asynchronously after the loader is enabled.

Therefore, a race condition is possible when defining the loader callback, where Polar has called the callbacks before the API-dependant plugin has registered one. In this case, the callback will not be called.

As a possible solution, the callback should be either registered in the onLoad sequence, or check if the PolarApiAccessor class has already been loaded before establishing a callback.

Listening to events

Polar API has a custom-built event system, which is completely independent of Bukkit events.

Events are registered through EventListenerRepository, which is accessible by using the PolarApi reference returned by PolarApiAccessor.

var listener = api.events().repository().registerListener(...);

The listener may then be unregistered through

api.events().repository().unregisterListener(listener);

Important remarks

API interface class implementations are not direct objects but object accessors instead. The wrapped object will be garbage collected afterwards.

Do not attempt to store API interfaces within the software - create POJOs with interface data instead.

Thread safety

  • PolarApiAccessor#access() is synchronized.

  • API calls are thread safe.

  • User-related events are called in the netty thread allocated to the user concerned.

  • Cloud-related events are called in the main cloud thread.