Action System
The action system is the core execution pipeline of EmakiCoreLib, providing unified action definition, parsing, and execution capabilities. All modules can trigger in-game behaviors through the action system.
Action Line Syntax
Each action follows this format:
[@if=<cond>] [@chance=<prob>] [@delay=<delay>] [@ignore_failure] <actionId> [key=value ...]| Part | Required | Description |
|---|---|---|
@if=<cond> | No | Condition prefix — executes only when the condition is true |
@chance=<prob> | No | Probability prefix — value between 0.0 and 1.0 |
@delay=<delay> | No | Delay prefix — in ticks (20 ticks = 1 second) |
@ignore_failure | No | Ignore failure — continues subsequent actions even if this one fails |
<actionId> | Yes | Action identifier (see built-in action list below) |
key=value ... | Depends | Action parameters as space-separated key-value pairs |
Control Prefixes
@if — Conditional Execution
Executes the action only when the condition expression evaluates to true. See Condition System for condition syntax details.
actions:
- "@if=%player_level%>=10 givemoney amount=500"
- "@if=%player_world%==world_nether sendmessage message=<red>你正在地狱中!"@chance — Probabilistic Execution
Executes the action with the specified probability, ranging from 0.0 (never) to 1.0 (always).
actions:
- "@chance=0.5 givemoney amount=1000" # 50% chance to give 1000 coins
- "@chance=0.1 createitem source=vanilla-diamond_sword amount=1" # 10% chance to give a diamond sword@delay — Delayed Execution
Delays execution by the specified number of ticks. 20 ticks = 1 second.
actions:
- "sendmessage message=<yellow>3 秒后传送..."
- "@delay=60 teleport world=world x=0 y=100 z=0" # Teleport after 3 seconds delay@ignore_failure — Ignore Failure
By default, a failed action interrupts the subsequent action chain. With this prefix, subsequent actions continue even if the current action fails.
actions:
- "@ignore_failure takemoney amount=500" # Continue even if deduction fails
- "sendmessage message=<green>流程继续执行"Combined Usage
Control prefixes can be freely combined:
actions:
- "@if=%player_level%>=20 @chance=0.3 @delay=20 givemoney amount=2000"Tip
The evaluation order of control prefixes is: @if → @chance → @delay → execute action. The condition is checked first, then the dice is rolled, and finally the delayed execution is scheduled.
Common Parameter Formats
Time Format
Some parameters support time format with the following syntax:
| Syntax | Meaning | Example |
|---|---|---|
40 | 40 ticks (no unit defaults to ticks) | duration=40 |
40t | 40 ticks | duration=40t |
2s | 2 seconds = 40 ticks | duration=2s |
100ms | 100 milliseconds ≈ 2 ticks | duration=100ms |
Coordinate Format
Coordinate parameters support absolute values and relative offsets:
| Syntax | Meaning |
|---|---|
100.5 | Absolute coordinate 100.5 |
~ | Player's current position |
~5 | Player's current position + 5 |
~-3 | Player's current position - 3 |
Built-in Action List
Message Actions
sendmessage
Send a chat message to the player.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
text | Yes | string | — | Message content, supports MiniMessage format |
actions:
- "sendmessage text=<green>Welcome back, %player_name%!"sendactionbar
Send an ActionBar message to the player.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
text | Yes | string | — | Message content, supports MiniMessage format |
broadcastmessage
Broadcast a message to all players. Does not require player context.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
text | Yes | string | — | Message content, supports MiniMessage format |
sendtitle
Send a title to the player.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
title | Yes | string | — | Main title, supports MiniMessage |
subtitle | No | string | "" | Subtitle, supports MiniMessage |
fade_in | No | time | 10t | Fade-in duration |
stay | No | time | 40t | Stay duration |
fade_out | No | time | 10t | Fade-out duration |
actions:
- "sendtitle title=<gold>Congratulations subtitle=<yellow>You leveled up! fade_in=10 stay=40 fade_out=10"Effect Actions
playsound
Play a sound to the player.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
sound | Yes | string | — | Sound key (Bukkit Sound enum name, case-insensitive) |
volume | No | double | 1.0 | Volume |
pitch | No | double | 1.0 | Pitch |
actions:
- "playsound sound=entity.player.levelup volume=1.0 pitch=1.0"spawnparticle
Spawn particles at a specified location.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
particle | Yes | string | — | Particle key (Bukkit Particle enum name, case-insensitive) |
count | No | int | 1 | Particle count |
target | No | string | "player" | Spawn location: player = player position, location = specified coordinates |
world | No | string | "" | World name (only for target=location) |
x | No | string | "" | X coordinate, supports relative format (only for target=location) |
y | No | string | "" | Y coordinate, supports relative format (only for target=location) |
z | No | string | "" | Z coordinate, supports relative format (only for target=location) |
offset_x | No | double | 0 | X-axis random offset |
offset_y | No | double | 0 | Y-axis random offset |
offset_z | No | double | 0 | Z-axis random offset |
extra | No | double | 0 | Extra parameter (speed/color etc., depends on particle type) |
actions:
- "spawnparticle particle=HEART count=10 offset_x=0.5 offset_y=0.5 offset_z=0.5"
- "spawnparticle particle=FLAME count=20 target=location world=world x=~0 y=~2 z=~0"Economy Actions
givemoney, takemoney, and setmoney share the same parameters, corresponding to give, deduct, and set balance respectively.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
amount | Yes | double | — | Amount |
provider | No | string | "auto" | Economy provider, see table below |
currency | No | string | "" | Currency ID (required for ExcellentEconomy) |
Provider options:
| Value | Behavior |
|---|---|
auto (default) | If currency is non-empty → ExcellentEconomy; otherwise → Vault |
vault | Force Vault |
excellenteconomy | Force ExcellentEconomy (must also specify currency) |
actions:
# Use default provider (Vault)
- "givemoney amount=100"
# Specify ExcellentEconomy with a specific currency
- "takemoney amount=50 provider=excellenteconomy currency=gems"
# Set balance
- "setmoney amount=1000 provider=vault"Warning
takemoney returns an ECONOMY_INSUFFICIENT error and interrupts the action chain when balance is insufficient. Add @ignore_failure prefix to continue.
Item Actions
createitem
Create a temporary item and store it in context. Use senditem to deliver it to the player.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
id | Yes | string | — | Temporary item ID (referenced by senditem / clearitem) |
source | No | string | "" | Item source, see source prefix table below. Aliases: item, item_source |
amount | No | int | 1 | Quantity, minimum 1 |
senditem
Send a temporary item to the player's inventory. Drops on ground if inventory is full.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
id | Yes | string | — | Temporary item ID (created by createitem) |
keep | No | boolean | false | true = keep in temp storage after sending; false = remove after sending |
clearitem
Clear an item from a specific player slot.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
slot | Yes | string | — | Slot, see slot table below |
source | No | string | "" | If specified, only clears when the slot item matches this source. Aliases: item, item_source |
Slot options:
| Value | Description |
|---|---|
mainhand / main_hand / hand | Main hand |
offhand / off_hand | Off hand |
helmet | Helmet |
chestplate / chest | Chestplate |
leggings / legs | Leggings |
boots | Boots |
0 ~ 35 | Inventory slot index |
hotbar_0 ~ hotbar_8 | Hotbar |
Item source prefixes:
| Prefix | Plugin | Example |
|---|---|---|
minecraft- / mc- / v- | Vanilla | minecraft-diamond_sword |
mmoitems- / mi- | MMOItems | mmoitems-SWORD:my_sword |
itemsadder- / ia- | ItemsAdder | itemsadder-namespace:item_id |
neigeitems- / ni- | NeigeItems | neigeitems-item_id |
nexo- / no- | Nexo | nexo-item_id |
craftengine- / ce- | CraftEngine | craftengine-namespace:item_id |
| No prefix | Vanilla (fallback) | diamond_sword |
actions:
- "createitem id=reward source=minecraft-diamond_sword amount=1"
- "senditem id=reward"
- "clearitem slot=offhand"Warning
Item sources use - as the separator, not :. Write minecraft-diamond_sword, not minecraft:diamond_sword. See Item Source System for details.
Player State Actions
teleport
Teleport the player to a specified location.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
x | Yes | string | — | X coordinate, supports relative format ~ / ~N |
y | Yes | string | — | Y coordinate, supports relative format |
z | Yes | string | — | Z coordinate, supports relative format |
world | No | string | "" | World name, empty = current world |
yaw | No | double | 0 | Horizontal facing (degrees) |
pitch | No | double | 0 | Vertical facing (degrees) |
actions:
- "teleport world=world x=0 y=100 z=0 yaw=90 pitch=0"
- "teleport x=~0 y=~10 z=~0" # Teleport 10 blocks upheal / damage / sethealth
| Action ID | Parameter | Required | Type | Description |
|---|---|---|---|---|
heal | amount | Yes | double | Restore health, capped at max health |
damage | amount | Yes | double | Deal damage, minimum 0 |
sethealth | amount | Yes | double | Set health, range [0, maxHealth] |
giveexp / takeexp / setexp
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
amount | Yes | int | — | Amount, minimum 0 |
mode | No | string | "points" | points = experience points; levels = levels |
actions:
- "giveexp amount=100"
- "giveexp amount=5 mode=levels" # Give 5 levels
- "takeexp amount=50 mode=points"Potion Effect Actions
givepotioneffect
Apply a potion effect to the player.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
type | Yes | string | — | Potion effect ID (e.g., speed, strength, regeneration) |
level | Yes | int | — | Level (1 = amplifier 0, 2 = amplifier 1, etc.) |
duration | Yes | time | — | Duration, supports time format |
ambient | No | boolean | false | Whether it's an ambient effect (sparser particles) |
particles | No | boolean | true | Whether to show particles |
icon | No | boolean | true | Whether to show HUD icon |
type format: Use Minecraft vanilla effect IDs like speed, strength, minecraft:regeneration. Namespace minecraft: is auto-prepended if omitted. Spaces are replaced with _.
removepotioneffect
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
type | Yes | string | — | Potion effect ID (same as above) |
clearpotioneffects
No parameters. Clears all potion effects from the player.
actions:
- "givepotioneffect type=speed level=2 duration=10s ambient=false particles=true"
- "removepotioneffect type=poison"
- "clearpotioneffects"Command Actions
runcommandasplayer
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
command | Yes | string | — | Command executed as the player (leading / is auto-removed) |
runcommandasop
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
command | Yes | string | — | Executed with temporary OP privileges, restored after execution |
runcommandasconsole
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
command | Yes | string | — | Executed as console, no player context required |
actions:
- "runcommandasplayer command=spawn"
- "runcommandasop command=gamemode creative %player_name%"
- "runcommandasconsole command=say Server announcement: %player_name% earned an achievement!"Warning
runcommandasop temporarily grants the player OP privileges — use with caution.
Template Actions
usetemplate
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
name | Yes | string | — | Template name (defined in config.yml under action.templates) |
actions:
- "usetemplate name=level_up_reward"Attribute Actions (EmakiAttribute Extension)
attribute_add
Stack a temporary attribute. Same effect_id repeated calls accumulate value and refresh expiry.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
effect_id | Yes | string | — | Unique effect identifier for later removal or override |
attribute | Yes | string | — | Attribute ID (e.g., physical_attack) |
value | Yes | double | — | Attribute value to stack |
duration_ticks | Yes | time | — | Duration, must be > 0, supports time format |
attribute_set
Override a temporary attribute. Directly sets the attribute value; later writes override earlier ones.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
effect_id | Yes | string | — | Unique effect identifier |
attribute | Yes | string | — | Attribute ID |
value | Yes | double | — | Attribute value to set |
duration_ticks | Yes | time | — | Duration, must be > 0, supports time format |
attribute_remove
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
effect_id | Yes | string | — | Effect ID to remove |
actions:
# Stack 50 physical attack for 10 seconds
- "attribute_add effect_id=buff_atk attribute=physical_attack value=50 duration_ticks=10s"
# Override physical defense to 100 for 200 ticks
- "attribute_set effect_id=override_def attribute=physical_defense value=100 duration_ticks=200"
# Remove specified effect
- "attribute_remove effect_id=buff_atk"Tip
Temporary attribute data exists only in memory and is lost on server restart. For persistent buffs across restarts, use PDC attributes instead.
attributedamage
Deal attribute damage to the player through EmakiAttribute's damage calculation pipeline.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
amount | Yes | double | — | Base damage value |
type | No | string | "" | Damage type ID, empty = use default damage type |
cause | No | string | "CUSTOM" | Bukkit DamageCause enum name (uppercase) |
Common cause values: CUSTOM, MAGIC, FIRE, FALL, POISON, PROJECTILE, ENTITY_ATTACK
actions:
- "attributedamage amount=50 type=spell cause=MAGIC"ActionContext
Each time an action is executed, the system creates an ActionContext object carrying the context information needed for execution.
| Field | Type | Description |
|---|---|---|
sourcePlugin | Plugin | The plugin instance that triggered the action |
player | Player | Target player |
phase | String | Current execution phase identifier (e.g., on_click, on_complete) |
silent | boolean | Whether in silent mode (no feedback messages sent) |
placeholders | Map<String, String> | Custom placeholder mappings |
attributes | Map<String, Object> | Additional attributes (can pass arbitrary objects) |
sharedState | Map<String, Object> | Shared state within the same action chain |
ActionContext context = ActionContext.builder()
.sourcePlugin(plugin)
.player(player)
.phase("on_reward")
.silent(false)
.placeholder("reward_amount", "500")
.placeholder("reward_type", "金币")
.attribute("source_event", event)
.build();
actionService.execute(actionLines, context);Tip
sharedState is shared across all actions within the same action chain and can be used to pass intermediate results between actions. For example, a preceding action can store a computed result in sharedState, and subsequent actions can read and use it.
Template System
Action templates allow you to define commonly used action combinations as reusable templates, avoiding repetitive writing.
Defining Templates
Define templates under the action.templates node in config.yml:
action:
templates:
level_up_reward:
- "playsound sound=entity.player.levelup volume=1.0 pitch=1.0"
- "spawnparticle particle=TOTEM count=30 offsetX=1 offsetY=1 offsetZ=1"
- "sendtitle title=<gold>升级! subtitle=<yellow>恭喜你升级了 fadeIn=10 stay=40 fadeOut=10"
- "givemoney amount=500"
- "giveexp amount=100"
error_feedback:
- "playsound sound=entity.villager.no volume=1.0 pitch=0.8"
- "sendmessage message=<red>操作失败,请稍后再试。"Using Templates
Reference templates in any action list via usetemplate:
actions:
- "sendmessage message=<green>你完成了任务!"
- "usetemplate template=level_up_reward"Actions within a template are expanded and executed in order. Control prefixes also apply to usetemplate:
actions:
- "@if=%quest_completed%==true @chance=0.5 usetemplate template=level_up_reward"Placeholder System
Action parameters can use %placeholder% format placeholders, which are replaced with actual values at execution time.
Built-in Placeholders
| Placeholder | Description |
|---|---|
%player_name% | Player name |
%player_uuid% | Player UUID |
%player_world% | Player's current world name |
%player_x% | Player's X coordinate |
%player_y% | Player's Y coordinate |
%player_z% | Player's Z coordinate |
%phase% | Current execution phase |
Custom Placeholders
Key-value pairs passed through ActionContext's placeholders can be used directly as placeholders:
ActionContext context = ActionContext.builder()
.player(player)
.placeholder("item_name", "钻石剑")
.placeholder("item_count", "3")
.build();actions:
- "sendmessage message=<green>你获得了 %item_count% 个 %item_name%!"Item Display Tag
Use the <show_item> tag to embed an item's hover display in chat messages:
actions:
- "sendmessage message=<green>你获得了 <show_item>!"Tip
<show_item> renders as a hoverable item display showing the item's name, lore, enchantments, and other details. It requires a corresponding ItemStack in the ActionContext's attributes.
PlaceholderAPI Integration
When PlaceholderAPI is installed on the server, CoreLib automatically recognizes and resolves PAPI placeholders. You can use any registered PAPI placeholder directly in action parameters:
actions:
- "sendmessage message=<gray>你的余额:%vault_eco_balance%"
- "@if=%statistic_play_one_minute%>=72000 sendmessage message=<gold>你已游玩超过 1 小时!"Tip
CoreLib built-in placeholders take priority over PlaceholderAPI. If a placeholder with the same name exists, the CoreLib built-in value will be used.
Error Types
The following error types may occur during action execution:
| Error Enum | Description |
|---|---|
UNKNOWN_ACTION | Unknown action ID |
INVALID_SYNTAX | Action line syntax error |
MISSING_PARAMETER | Missing required parameter |
INVALID_PARAMETER | Invalid parameter value |
CONDITION_NOT_MET | Condition not satisfied (not an error, normal skip) |
CHANCE_NOT_MET | Probability not hit (not an error, normal skip) |
EXECUTION_FAILED | Exception occurred during action execution |
PLAYER_OFFLINE | Target player is offline |
ECONOMY_INSUFFICIENT | Insufficient economy balance |
ITEM_SOURCE_NOT_FOUND | Item source could not be resolved |
TEMPLATE_NOT_FOUND | Referenced template does not exist |
actionService.execute(actionLines, context).whenComplete((result, ex) -> {
if (result.hasErrors()) {
for (ActionError error : result.getErrors()) {
logger.warning("动作执行错误: " + error.type() + " - " + error.message());
}
}
});