English
API and Integration
Third-party plugins reach EmakiStation through emaki-station-api
Maven Coordinates
xml
<dependency>
<groupId>emaki.jiuwu.craft</groupId>
<artifactId>emaki-station-api</artifactId>
<version>1.1.7</version>
<scope>provided</scope>
</dependency>Do not put emaki-station-api-*.jar into the server plugins/ folder. It is a compile-time artifact only
Declare EmakiStation as a dependency in your paper-plugin.yml:
yaml
dependencies:
server:
EmakiStation:
load: BEFORE
required: false
join-classpath: trueFacade
emaki.jiuwu.craft.station.api.EmakiStationApi is the static facade:
| Method | Description |
|---|---|
status() | Availability and identity metadata, returning CoreLib's ApiStatus |
catalog() | Query layer, see StationCatalog below |
operations() | Operation layer, see StationOperations below |
extensions() | Reserved extension surface; currently an empty interface |
install(Bridge) / uninstall(Bridge) | For EmakiStation's own lifecycle only; annotated @ApiStatus.Internal |
Accessors never return null. While EmakiStation is absent, every layer returns an explicit FailureKind.UNAVAILABLE result; callers must not use a NullPointerException as an availability signal
status() derives its three text fields from the bridge: pluginName is EmakiStation, pluginVersion is the module version from the descriptor (1.1.8), and apiVersion is the bridge's built-in contract constant "1.0.0". apiVersion is not the version of the emaki-station-api artifact, so never use it to decide which API artifact version to depend on
Bridge is annotated @ApiStatus.NonExtendable; third-party plugins must not implement it
Readiness Criterion
status().ready() is backed by the module's contentReady (configuration, stations and recipes have finished loading), not by "the service object is non-null". During a reload it is false, and the operation layer returns UNAVAILABLE rather than disguising a timing problem as "the data does not exist"
Combine it with CoreLib's cross-module readiness contract:
java
EmakiCoreLibApi.whenReady(myPlugin, "EmakiStation", () -> {
// EmakiStation recipes and stations are loaded
});To invalidate your own cache after every EmakiStation reload, register the resident listener once instead of re-registering whenReady inside the callback:
java
EmakiCoreLibApi.addModuleListener(myPlugin, "EmakiStation", phase -> {
if (phase == ModuleReadinessPhase.READY) {
rebuildMyCache();
}
});StationCatalog — Query Layer
Annotated @ApiStatus.NonExtendable. The synchronous methods read configuration that has already loaded, and they are safe to call from any thread
| Method | Description |
|---|---|
List<StationView> stations() | List every loaded station in stable id order; empty while the runtime is unavailable |
Optional<StationView> station(String stationId) | Look up a station by id |
List<RecipeView> recipes() | List every recipe |
Optional<RecipeView> recipe(String recipeId) | Look up a recipe by id |
List<RecipeView> recipesOf(String stationId) | List the recipes offered by one station |
CompletableFuture<EmakiResult<QueueSnapshot>> queueSnapshotAsync(UUID playerId, String stationId) | Read a detached snapshot of one player's queue at one station |
queueSnapshotAsync is asynchronous because a queue that is not cached must be read from disk. It works for offline players: queue data is per-player file state and does not require the owner to be present. A player with no entries yields an empty queue rather than a failure
Do not assume that the future completes on an owner thread
StationOperations — Operation Layer
Annotated @ApiStatus.NonExtendable
| Method | Thread | Description |
|---|---|---|
CompletableFuture<EmakiResult<SubmitOutcome>> submitAsync(UUID playerId, String stationId, String recipeId, long batch, MaterialChannel channel) | Any thread; requires the target player online | Submit a craft. batch must be positive |
CompletableFuture<EmakiResult<Unit>> cancelAsync(UUID playerId, String stationId, int index) | Any thread; requires the target player online | Cancel one queue entry; index is zero-based |
CompletableFuture<EmakiResult<Integer>> claimAsync(UUID playerId) | Any thread; requires the target player online | Claim every deliverable pending output across all stations; the payload counts the entries actually cleared |
EmakiResult<Unit> openGui(Player player, String stationId) | Must run on that player's owner thread | Open a station window |
The channel Parameter of submitAsync Is Inert
Materials come from a single merged pool spanning the player's inventory and their warehouse, spent inventory-first. channel therefore no longer selects anything and is ignored; the parameter is retained for source compatibility only
Two consequences for existing callers: passing MaterialChannel.BACKPACK is no longer refused (the historical station.api_backpack_unsupported reason key is no longer produced), and a submission may draw on the inventory even when MaterialChannel.STORAGE was requested
Failure Reason Keys of the Operation Layer
submitAsync returns station.submit_bad_request / station.bad_batch for null arguments and batch <= 0, and UNAVAILABLE while the module is not ready. cancelAsync and claimAsync return targetOffline() when the target player is offline, and cancelAsync additionally returns station.unknown_station for an unknown station
openGui can return station.open_bad_request, UNAVAILABLE, station.unknown_station, station.queue_not_loaded, station.missing_layout or FailureKind.WRONG_THREAD
Refund Semantics of cancelAsync
Refunds always return to the channel each material came from, independent of the station's output routing. A partially refunded cancellation still reports success and carries the shortfall as a Partial reason key
openGui Is Deliberately Synchronous
openGui touches the viewer and their inventory window immediately, so it must run on the supplied player's owner thread: on Folia that is the entity scheduler owner, on Paper it is the main server thread. A call from any other thread returns FailureKind.WRONG_THREAD and never schedules a later open on the caller's behalf
Model Types
The emaki.jiuwu.craft.station.api.model package:
| Type | Description |
|---|---|
StationView | Station view |
RecipeView | Recipe view |
MaterialRequirementView | Material requirement view |
QueueSnapshot | Queue snapshot |
QueueEntryView | Queue entry view |
QueueEntryState | Entry state: WAITING, RUNNING, PENDING_CLAIM |
ConsumedMaterial | Record of a consumed material |
PendingOutput | An output awaiting delivery |
SubmitOutcome | Submission result payload |
MaterialChannel | Material channel enum; ignored by submitAsync |
OutputRouting | Output routing |
ProgressMode | Progression mode |