Skip to content

Event API ​

EmakiStation publishes three Bukkit events in the emaki.jiuwu.craft.station.api.event package

EventCancellableFiresThread
StationCraftSubmitEventYesBefore any charge or material deductionSee the note below (the API path does not guarantee the owner thread)
StationCraftCancelEventYesBefore the queue entry is removed and refundedThe queue owner's owner thread
StationCraftCompletedEventNoAfter settlement completes and outputs are routedThe crafting player's owner thread

The latter two always fire through the entity's owner dispatch: on Folia that is the entity scheduler owner, on Paper the main server thread

StationCraftSubmitEvent also fires on the owner thread for the GUI and command paths, but the API's submitAsync accepts any calling thread and dispatches the event directly on that calling thread, so listeners must not assume it always runs on the owner thread -- switch back to the owner yourself before touching player state

StationCraftSubmitEvent ​

java
public class StationCraftSubmitEvent extends Event implements Cancellable
MemberTypeDescription
getPlayer()PlayerThe submitting player
getStationId()StringStation id
getRecipeId()StringRecipe id
getBatch()longThe multiplier of this submission
getChannel()MaterialChannelThe channel carried by the event. The bridge derives it from the station configuration: STORAGE when the station enables channels.storage and the warehouse channel is usable, otherwise BACKPACK. It does not report which channel this submission actually debits
isCancelled() / setCancelled(boolean)booleanCancellation control

Cancelling stops the whole submission: nothing is charged, nothing is deducted, no queue entry is created. This is the only point where a craft can be vetoed at zero compensation

Coverage: any submission that passed pre-validation (station/recipe resolution, batch, recipe availability, permission, condition gate, queue capacity, pending-claim ceiling) and reached the charging stage, whether it came from the GUI, a command or StationOperations#submitAsync. The event fires before the material and balance checks, so submissions that later fail on insufficient materials or balance still fire it

It does not fire for submissions refused earlier by permissions, conditions, queue capacity or the pending-claim ceiling, and it does not fire when a queue entry later advances or settles

StationCraftCancelEvent ​

java
public class StationCraftCancelEvent extends Event implements Cancellable
MemberTypeDescription
getPlayer()PlayerThe queue owner
getStationId()StringStation id
getRecipeId()StringRecipe id
getIndex()intQueue position, zero-based
getConsumedMaterials()List<ConsumedMaterial>The materials this entry consumed
getRefundRate()doubleThe refund fraction about to be applied
isCancelled() / setCancelled(boolean)booleanCancellation control

Cancelling keeps the entry in the queue and refunds nothing, so the player's materials stay invested in that craft. A vetoed cancellation reports FailureKind.CANCELLED with the reason key station.cancel_vetoed

getRefundRate() comes from the station's queue.cancel_refund_rate

Coverage: cancellations a player triggers from the GUI or a command, plus StationOperations#cancelAsync. It does not fire when an entry completes normally, nor when queue data is discarded administratively

Entries in the PENDING_CLAIM state are refused before this event fires, returning station.cancel_pending_claim, so listeners never observe that kind of cancellation

StationCraftCompletedEvent ​

java
public class StationCraftCompletedEvent extends Event

Not cancellable: by the time it fires the materials are long spent and the outputs are already delivered or parked, leaving nothing to veto

MemberTypeDescription
getPlayer()PlayerThe crafting player
getStationId()StringStation id
getRecipeId()StringRecipe id
getBatch()longThe multiplier settled
getDeliveredOutputs()List<PendingOutput>Outputs delivered successfully
getPendingOutputs()List<PendingOutput>Outputs that could not be delivered and became pending-claim

Coverage: settlement of a queue entry, plus immediate settlement of a zero-duration recipe

A non-empty getPendingOutputs() means no configured target could accept the outputs, and they now await a manual claim. "Completed" therefore describes the craft itself, not successful delivery

This event does not fire when the player later claims parked outputs, and it is not an audit log: cancelled entries never reach it

Examples ​

java
@EventHandler(ignoreCancelled = true)
public void onSubmit(StationCraftSubmitEvent event) {
    if (isBlacklisted(event.getRecipeId())) {
        event.setCancelled(true);
    }
}

@EventHandler
public void onCompleted(StationCraftCompletedEvent event) {
    if (!event.getPendingOutputs().isEmpty()) {
        event.getPlayer().sendMessage("Some outputs could not be delivered. Free up space and claim them.");
    }
}

Both event classes defensively copy the lists passed to their constructors, turning null into an empty list