Skip to main content

Triggers and Subscriptions

A trigger consists of two parts: "a game event publishes a signal" and "a rule or subscription matches the signal". Trigger stores only the matching parameters, while TriggerRule combines matching with conditions, chance, cooldown and entity actions.

Responding to events with a data pack​

data/example/saturn/trigger/first_diamond.json
{
"trigger": {
"type": "saturn:advancement_completed",
"advancement": "minecraft:story/mine_diamond"
},
"action": {
"type": "saturn:send_message",
"message": { "text": "Diamond advancement completed" }
}
}

For the structure see Trigger rules; for every matching type see the trigger catalogue. Vanilla criterion port types reuse the JSON parameters of the corresponding criterion: Saturn bridges the event or polls the state and does not create advancements.

Java subscriptions​

TriggerDispatcher.register(new TriggerSubscription(
player.getUUID(), "example:module", "first_diamond",
new AdvancementCompletedTrigger(
Optional.of(Identifier.parse("minecraft:story/mine_diamond"))),
signal -> true,
signal -> handleCompletion(player, signal),
false
));

owner is the player or entity UUID; module and identity only need to be unique within this owner. The gate additionally filters matching results; the listener runs synchronously on the server, so expensive requests should be handed to the caller's worker thread. oneShot=true consumes this in-memory subscription after the callback returns successfully; it does not mean the persisted business has already completed.

Clean up your own subscriptions with clearModule(owner, module). Subscriptions are not saved to disk; after an entity joins, the server starts or a data pack reloads, rebuild them from the state saved by the host with TriggerRehydrateEvent.rehydrate(module, rebuild); Saturn clears the index when an entity leaves and when the server shuts down.

Publishing custom signals​

TriggerPublishing.publish(type, actor, FormulaContext, enrich) first checks the listeners and then builds the context. TriggerContext contains actor, target, level, position, item, block, damageSource and formula values; extra objects use namespaced payload keys. TriggerDispatcher.publish handles data pack rules first and then the actor's subscriptions, filtering out FakePlayer.

Boundaries of advancement events​

saturn:advancement_completed is published when the whole advancement completes. The payload's TriggerPayload.ADVANCEMENT is an Identifier. Omitting the filter ID includes hidden advancements and recipe unlocks. It is not re-sent on login; completing an advancement again after it was revoked publishes again.

System still uses its own advancement rules, binding baseline and event ledger; this entry point is reserved in the current Saturn source and has not yet replaced System's listener. If the business requires that a reward is only granted once, the business storage should record an idempotency key instead of relying only on oneShot.