API
EmakiCodexApi is EmakiCodex's static public API facade for third-party plugins. Depend on emaki-codex-api at compile time; the installed EmakiCodex plugin provides the runtime implementation.
Server owners install only EmakiCodex-*.jar. Do not put emaki-codex-api-*.jar into the server plugins/ directory.
Maven dependency
<dependency>
<groupId>emaki.jiuwu.craft</groupId>
<artifactId>emaki-codex-api</artifactId>
<version>1.0.0</version>
<scope>provided</scope>
</dependency>If your plugin is built with Maven, make sure the runtime server has the same or a newer EmakiCodex plugin installed.
Gradle dependency
dependencies {
compileOnly("emaki.jiuwu.craft:emaki-codex-api:1.0.0")
}Availability checks
import emaki.jiuwu.craft.codex.api.EmakiCodexApi;
if (!EmakiCodexApi.available() || !EmakiCodexApi.isReady()) {
return;
}available() means the Codex API bridge is installed. isReady() means the plugin is enabled and initialized.
You can also use the migration helper:
import emaki.jiuwu.craft.codex.api.EmakiCodexApiProvider;
if (EmakiCodexApiProvider.available()) {
EmakiCodexApiProvider.requireAvailable();
}EmakiCodexApiProvider is only an availability helper; it is not an instance service entry point.
Grant a node
import java.util.UUID;
import emaki.jiuwu.craft.codex.api.EmakiCodexApi;
UUID playerId = player.getUniqueId();
boolean changed = EmakiCodexApi.grantAdvancement(playerId, "example/first_step");
if (!changed) {
// The player is offline, the calling thread does not own the player, the node is not registered, or the player already completed it.
}The synchronous methods require the calling thread to already own the target player. When it does not, they return false immediately. Use the asynchronous overloads below when ownership is unclear.
advancementId supports two forms:
| Form | Example |
|---|---|
| Short form | example/first_step |
| Full key | emakicodex:example/first_step |
Granting a node awards the internal codex criterion. On first completion, the vanilla completion flow runs and the node's actions.complete list executes.
Revoke a node
import java.util.UUID;
import emaki.jiuwu.craft.codex.api.EmakiCodexApi;
UUID playerId = player.getUniqueId();
boolean changed = EmakiCodexApi.revokeAdvancement(playerId, "example/first_step");
if (!changed) {
// The player is offline, the calling thread does not own the player, the node is not registered, or the player has not completed it.
}Revoke only affects registered Codex nodes. It does not delete configuration files and does not remove advancement definitions from the server registry.
Asynchronous writes
When you are not sure whether the current thread owns the target player, use the asynchronous overloads and let EmakiCodex dispatch to the correct owner thread:
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import emaki.jiuwu.craft.codex.api.EmakiCodexApi;
CompletableFuture<Boolean> future =
EmakiCodexApi.grantAdvancementAsync(playerId, "example/first_step");
future.thenAccept(changed -> {
// The callback thread is not guaranteed to be the main thread.
});| Method | Returns | Description |
|---|---|---|
grantAdvancementAsync(UUID, String) | CompletableFuture<Boolean> | Grants a node asynchronously. Returns a completed false when the API is unavailable. |
revokeAdvancementAsync(UUID, String) | CompletableFuture<Boolean> | Revokes a node asynchronously. Returns a completed false when the API is unavailable. |
These methods do not promise a thread switch: the returned future may already be complete when the player is offline, the API is unavailable, or scheduling fails. Callbacks that touch Bukkit/Paper/Folia state must dispatch to the correct owner thread themselves.
Version and plugin name
String version = EmakiCodexApi.apiVersion();
String pluginName = EmakiCodexApi.pluginName();When the API is unavailable, both methods return an empty string.
Integration boundaries
- The API exposes only a static facade. It does not expose
AdvancementService, loaders, listeners, or configuration parsers. - API methods target online player UUIDs. Offline players are not loaded or modified.
- If you want to grant nodes from configured action chains, prefer CoreLib Actions. Use
EmakiCodexApifor third-party plugin code integration. - The current public API does not expose a resync method for refreshing the player's client advancement tree. Use the
codex_resync_advancementCoreLib action when you need that behavior.