Event API
EmakiStation publishes three Bukkit events in the emaki.jiuwu.craft.station.api.event package.
All three fire on the crafting player's owner thread: on Folia that is the entity scheduler owner, on Paper the main server thread.
| Event | Cancellable | Fires |
|---|---|---|
StationCraftSubmitEvent | Yes | Before any charge or material deduction. |
StationCraftCancelEvent | Yes | Before the queue entry is removed and refunded. |
StationCraftCompletedEvent | No | After settlement completes and outputs are routed. |
StationCraftSubmitEvent
public class StationCraftSubmitEvent extends Event implements Cancellable| Member | Type | Description |
|---|---|---|
getPlayer() | Player | The submitting player. |
getStationId() | String | Station id. |
getRecipeId() | String | Recipe id. |
getBatch() | long | The multiplier of this submission. |
getChannel() | MaterialChannel | Material channel; no longer decides where materials come from. |
isCancelled() / setCancelled(boolean) | boolean | Cancellation 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 reaches the charging stage, whether it came from the GUI, a command or StationOperations#submitAsync. It does not fire for submissions rejected earlier by permissions, conditions, queue capacity or material checks, and it does not fire when a queue entry later advances or settles.
StationCraftCancelEvent
public class StationCraftCancelEvent extends Event implements Cancellable| Member | Type | Description |
|---|---|---|
getPlayer() | Player | The queue owner. |
getStationId() | String | Station id. |
getRecipeId() | String | Recipe id. |
getIndex() | int | Queue position, zero-based. |
getConsumedMaterials() | List<ConsumedMaterial> | The materials this entry consumed. |
getRefundRate() | double | The refund fraction about to be applied. |
isCancelled() / setCancelled(boolean) | boolean | Cancellation 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
public class StationCraftCompletedEvent extends EventNot cancellable: by the time it fires the materials are long spent and the outputs are already delivered or parked, leaving nothing to veto.
| Member | Type | Description |
|---|---|---|
getPlayer() | Player | The crafting player. |
getStationId() | String | Station id. |
getRecipeId() | String | Recipe id. |
getBatch() | long | The 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
@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.