Skip to content

动作系统 (Action System)

动作系统是 EmakiCoreLib 里最常打交道的部分之一。你可以把它理解为一条执行管线:给它一组动作指令,它会按顺序解析、判断条件、执行,并把结果反馈回来。所有模块都通过这套系统来触发游戏内的行为。

动作行语法

每条动作写成一行字符串,格式如下:

[@if=<cond>] [@chance=<prob>] [@delay=<delay>] [@ignore_failure] <actionId> [key=value ...]
部分必填说明
@if=<cond>条件前缀,条件为真时才执行
@chance=<prob>概率前缀,取值 0.0 ~ 1.0
@delay=<delay>延迟前缀,单位为 tick(20 tick = 1 秒)
@ignore_failure忽略失败,即使该动作执行失败也继续后续动作
<actionId>动作标识符(见下方内置动作列表)
key=value ...视动作而定动作参数,以空格分隔的键值对

方括号里的都是可选的控制前缀,可以按需组合。核心就是 actionId 加上它需要的参数。

控制前缀

控制前缀写在动作 ID 前面,用来决定这条动作"要不要执行"以及"什么时候执行"。

@if — 条件执行

只有条件表达式求值为 true 时才执行。条件的写法详见 条件系统

yaml
actions:
  - "@if=%player_level%>=10 givemoney amount=500"
  - "@if=%player_world%==world_nether sendmessage message=<red>你正在地狱中!"

@chance — 概率执行

按指定概率执行,0.0 表示永不执行,1.0 表示必定执行。适合做随机奖励、稀有掉落之类的场景。

yaml
actions:
  - "@chance=0.5 givemoney amount=1000"       # 50% 概率给予 1000 金币
  - "@chance=0.1 createitem source=vanilla-diamond_sword amount=1"  # 10% 概率给予钻石剑

@delay — 延迟执行

延迟指定 tick 数后再执行。20 tick = 1 秒,所以 @delay=60 就是 3 秒后执行。

yaml
actions:
  - "sendmessage message=<yellow>3 秒后传送..."
  - "@delay=60 teleport world=world x=0 y=100 z=0"   # 延迟 3 秒后传送

@ignore_failure — 忽略失败

默认情况下,一条动作执行失败会中断整个动作链。加上这个前缀后,即使当前动作失败也会继续往下走。

典型场景:扣款可能因余额不足而失败,但你不希望因此阻断后续流程。

yaml
actions:
  - "@ignore_failure takemoney amount=500"    # 即使扣款失败也继续
  - "sendmessage message=<green>流程继续执行"

组合使用

这些前缀可以自由叠加,系统会按固定顺序处理:

yaml
actions:
  - "@if=%player_level%>=20 @chance=0.3 @delay=20 givemoney amount=2000"

提示

求值顺序是 @if@chance@delay → 执行动作。也就是说,先看条件是否满足,再掷骰子,最后才安排延迟执行。如果条件不满足,后面的步骤直接跳过,不会白白消耗随机数。

通用参数格式

时间格式

部分参数支持时间格式,可以用以下写法:

写法含义示例
4040 tick(无单位默认 tick)duration=40
40t40 tickduration=40t
2s2 秒 = 40 tickduration=2s
100ms100 毫秒 ≈ 2 tickduration=100ms

坐标格式

坐标参数支持绝对值和相对偏移:

写法含义
100.5绝对坐标 100.5
~玩家当前位置
~5玩家当前位置 + 5
~-3玩家当前位置 - 3

内置动作列表

消息类

sendmessage

向玩家发送聊天消息。

参数必填类型默认值说明
textstring消息内容,支持 MiniMessage 格式
yaml
actions:
  - "sendmessage text=<green>欢迎回来,%player_name%!"

sendactionbar

向玩家发送 ActionBar 消息。

参数必填类型默认值说明
textstring消息内容,支持 MiniMessage 格式

broadcastmessage

向全服所有玩家广播消息,不需要 player 上下文。

参数必填类型默认值说明
textstring消息内容,支持 MiniMessage 格式

sendtitle

向玩家发送标题。

参数必填类型默认值说明
titlestring主标题,支持 MiniMessage
subtitlestring""副标题,支持 MiniMessage
fade_intime10t淡入时间
staytime40t停留时间
fade_outtime10t淡出时间
yaml
actions:
  - "sendtitle title=<gold>恭喜 subtitle=<yellow>你升级了! fade_in=10 stay=40 fade_out=10"

效果类

playsound

向玩家播放声音。

参数必填类型默认值说明
soundstring声音 key(Bukkit Sound 枚举名,大小写不敏感)
volumedouble1.0音量
pitchdouble1.0音调
yaml
actions:
  - "playsound sound=entity.player.levelup volume=1.0 pitch=1.0"

spawnparticle

在指定位置生成粒子。

参数必填类型默认值说明
particlestring粒子 key(Bukkit Particle 枚举名,大小写不敏感)
countint1粒子数量
targetstring"player"生成位置:player = 玩家位置,location = 指定坐标
worldstring""世界名(仅 target=location 时有效)
xstring""X 坐标,支持相对格式(仅 target=location
ystring""Y 坐标,支持相对格式(仅 target=location
zstring""Z 坐标,支持相对格式(仅 target=location
offset_xdouble0X 方向随机偏移
offset_ydouble0Y 方向随机偏移
offset_zdouble0Z 方向随机偏移
extradouble0额外参数(速度/颜色等,取决于粒子类型)
yaml
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"

经济类

givemoneytakemoneysetmoney 三个动作参数完全相同,分别对应给予、扣除、设置余额。

参数必填类型默认值说明
amountdouble金额
providerstring"auto"经济提供者,见下表
currencystring""货币 ID(ExcellentEconomy 时必须填)

provider 可选值:

行为
auto(默认)currency 非空 → 使用 ExcellentEconomy;否则 → 使用 Vault
vault强制使用 Vault
excellenteconomy强制使用 ExcellentEconomy(必须同时填 currency
yaml
actions:
  # 使用默认提供者(Vault)
  - "givemoney amount=100"

  # 指定 ExcellentEconomy 的特定货币
  - "takemoney amount=50 provider=excellenteconomy currency=gems"

  # 设置余额
  - "setmoney amount=1000 provider=vault"

注意

takemoney 在余额不足时会返回 ECONOMY_INSUFFICIENT 错误并中断动作链。如果不希望中断,加 @ignore_failure 前缀。


物品类

createitem

创建临时物品并存入上下文,后续通过 senditem 发送给玩家。

参数必填类型默认值说明
idstring临时物品 ID(后续 senditem / clearitem 引用)
sourcestring""物品来源,见下方来源前缀表。别名:itemitem_source
amountint1数量,最小为 1

senditem

将临时物品发送到玩家背包,背包满时掉落在脚下。

参数必填类型默认值说明
idstring临时物品 ID(由 createitem 创建)
keepbooleanfalsetrue = 发送后保留临时存储;false = 发送后移除

clearitem

清除玩家指定槽位的物品。

参数必填类型默认值说明
slotstring槽位,见下方槽位表
sourcestring""若指定,仅当槽位物品匹配该来源时才清除。别名:itemitem_source

slot 可选值:

说明
mainhand / main_hand / hand主手
offhand / off_hand副手
helmet头盔
chestplate / chest胸甲
leggings / legs护腿
boots靴子
0 ~ 35背包槽位索引
hotbar_0 ~ hotbar_8快捷栏

物品来源前缀:

前缀插件示例
minecraft- / mc- / v-原版minecraft-diamond_sword
mmoitems- / mi-MMOItemsmmoitems-SWORD:my_sword
itemsadder- / ia-ItemsAdderitemsadder-namespace:item_id
neigeitems- / ni-NeigeItemsneigeitems-item_id
nexo- / no-Nexonexo-item_id
craftengine- / ce-CraftEnginecraftengine-namespace:item_id
无前缀原版(回退)diamond_sword
yaml
actions:
  - "createitem id=reward source=minecraft-diamond_sword amount=1"
  - "senditem id=reward"
  - "clearitem slot=offhand"

注意

物品来源用 - 分隔,不是 :。写 minecraft-diamond_sword 而不是 minecraft:diamond_sword。详见 物品来源系统


玩家状态类

teleport

传送玩家到指定位置。

参数必填类型默认值说明
xstringX 坐标,支持相对格式 ~ / ~N
ystringY 坐标,支持相对格式
zstringZ 坐标,支持相对格式
worldstring""世界名,空 = 当前世界
yawdouble0水平朝向(度)
pitchdouble0垂直朝向(度)
yaml
actions:
  - "teleport world=world x=0 y=100 z=0 yaw=90 pitch=0"
  - "teleport x=~0 y=~10 z=~0"   # 向上传送 10 格

heal / damage / sethealth

动作 ID参数必填类型说明
healamountdouble恢复血量,不超过最大血量
damageamountdouble扣除血量,最低降至 0
sethealthamountdouble设置血量,范围 [0, maxHealth]

giveexp / takeexp / setexp

参数必填类型默认值说明
amountint数量,最小为 0
modestring"points"points = 经验点数;levels = 等级
yaml
actions:
  - "giveexp amount=100"
  - "giveexp amount=5 mode=levels"   # 给予 5 级
  - "takeexp amount=50 mode=points"

药水效果类

givepotioneffect

给予玩家药水效果。

参数必填类型默认值说明
typestring药水效果 ID(如 speedstrengthregeneration
levelint等级(1 = amplifier 0,2 = amplifier 1,以此类推)
durationtime持续时间,支持时间格式
ambientbooleanfalse是否为环境效果(粒子更稀疏)
particlesbooleantrue是否显示粒子
iconbooleantrue是否显示 HUD 图标

type 格式:使用 Minecraft 原版效果 ID,如 speedstrengthminecraft:regeneration。不带命名空间时自动补 minecraft: 前缀,空格自动替换为 _

removepotioneffect

参数必填类型默认值说明
typestring药水效果 ID(同上)

clearpotioneffects

无参数,清除玩家所有药水效果。

yaml
actions:
  - "givepotioneffect type=speed level=2 duration=10s ambient=false particles=true"
  - "removepotioneffect type=poison"
  - "clearpotioneffects"

命令类

runcommandasplayer

参数必填类型默认值说明
commandstring以玩家身份执行的命令(自动去除开头的 /

runcommandasop

参数必填类型默认值说明
commandstring以临时 OP 权限执行,执行后恢复原状态

runcommandasconsole

参数必填类型默认值说明
commandstring以控制台身份执行,无需 player 上下文
yaml
actions:
  - "runcommandasplayer command=spawn"
  - "runcommandasop command=gamemode creative %player_name%"
  - "runcommandasconsole command=say 服务器公告:%player_name% 获得了成就!"

注意

runcommandasop 会临时给玩家 OP 权限来执行命令,用的时候要小心。


模板类

usetemplate

参数必填类型默认值说明
namestring模板名称(在 config.ymlaction.templates 中定义)
yaml
actions:
  - "usetemplate name=level_up_reward"

属性类(EmakiAttribute 扩展)

attribute_add

叠加临时属性。同一个 effect_id 重复调用会累加数值并刷新过期时间。

参数必填类型默认值说明
effect_idstring效果唯一标识,用于后续移除或覆盖
attributestring属性 ID(如 physical_attack
valuedouble叠加的属性值
duration_tickstime持续时间,必须 > 0,支持时间格式

attribute_set

覆盖临时属性。直接设定属性值,后写入的覆盖先写入的。

参数必填类型默认值说明
effect_idstring效果唯一标识
attributestring属性 ID
valuedouble设置的属性值
duration_tickstime持续时间,必须 > 0,支持时间格式

attribute_remove

参数必填类型默认值说明
effect_idstring要移除的临时效果 ID
yaml
actions:
  # 叠加 50 点物理攻击,持续 10 秒
  - "attribute_add effect_id=buff_atk attribute=physical_attack value=50 duration_ticks=10s"

  # 覆盖物理防御为 100,持续 200 tick
  - "attribute_set effect_id=override_def attribute=physical_defense value=100 duration_ticks=200"

  # 移除指定效果
  - "attribute_remove effect_id=buff_atk"

提示

临时属性数据只存在内存中,服务器重启后会丢失。如果需要跨重启的持久 Buff,应该用 PDC 属性。

attributedamage

对玩家造成属性伤害,走 EmakiAttribute 的伤害计算流程。

参数必填类型默认值说明
amountdouble基础伤害值
typestring""伤害类型 ID,空 = 使用默认伤害类型
causestring"CUSTOM"Bukkit DamageCause 枚举名(大写)

cause 常用值:CUSTOMMAGICFIREFALLPOISONPROJECTILEENTITY_ATTACK

yaml
actions:
  - "attributedamage amount=50 type=spell cause=MAGIC"

ActionContext

每次执行动作时,系统会创建一个 ActionContext 来携带执行所需的上下文信息。你可以把它看作动作执行的"环境"。

字段类型说明
sourcePluginPlugin触发动作的插件实例
playerPlayer目标玩家
phaseString当前执行阶段标识(如 on_click, on_complete
silentboolean是否静默模式(不发送反馈消息)
placeholdersMap<String, String>自定义占位符映射
attributesMap<String, Object>附加属性(可传递任意对象)
sharedStateMap<String, Object>同一动作链中共享的状态
java
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);

提示

sharedState 在同一动作链的所有动作之间共享。比如前一个动作算出了某个结果,可以存进 sharedState,后面的动作直接读取。这在需要多步骤协作的场景下很有用。

模板系统

如果你发现好几个地方都在写相同的动作序列,可以把它们抽成模板。定义一次,到处引用。

定义模板

config.ymlaction.templates 下定义:

yaml
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>操作失败,请稍后再试。"

使用模板

在任何动作列表中用 usetemplate 引用即可:

yaml
actions:
  - "sendmessage message=<green>你完成了任务!"
  - "usetemplate template=level_up_reward"

模板里的动作会被展开并按顺序执行。控制前缀也可以加在 usetemplate 上,这样整个模板的执行都会受到控制:

yaml
actions:
  - "@if=%quest_completed%==true @chance=0.5 usetemplate template=level_up_reward"

占位符系统

动作参数里可以用 %placeholder% 格式的占位符,执行时会被替换成实际值。

内置占位符

占位符说明
%player_name%玩家名称
%player_uuid%玩家 UUID
%player_world%玩家所在世界名称
%player_x%玩家 X 坐标
%player_y%玩家 Y 坐标
%player_z%玩家 Z 坐标
%phase%当前执行阶段

自定义占位符

通过 ActionContextplaceholders 传入的键值对会直接变成可用的占位符:

java
ActionContext context = ActionContext.builder()
    .player(player)
    .placeholder("item_name", "钻石剑")
    .placeholder("item_count", "3")
    .build();
yaml
actions:
  - "sendmessage message=<green>你获得了 %item_count% 个 %item_name%!"

物品展示标签

<show_item> 标签可以在聊天消息里嵌入物品的悬浮展示,玩家把鼠标移上去就能看到物品的详细信息(名称、Lore、附魔等)。

yaml
actions:
  - "sendmessage message=<green>你获得了 <show_item>!"

提示

要让 <show_item> 正常工作,需要在 ActionContextattributes 里放入对应的 ItemStack 对象。

PlaceholderAPI 集成

如果服务器装了 PlaceholderAPI,CoreLib 会自动识别并解析 PAPI 占位符。你可以在动作参数里直接用任何已注册的 PAPI 占位符:

yaml
actions:
  - "sendmessage message=<gray>你的余额:%vault_eco_balance%"
  - "@if=%statistic_play_one_minute%>=72000 sendmessage message=<gold>你已游玩超过 1 小时!"

提示

CoreLib 内置占位符的优先级高于 PlaceholderAPI。如果两边有同名的占位符,会用 CoreLib 内置的值。

错误类型

动作执行过程中可能产生以下错误。其中 CONDITION_NOT_METCHANCE_NOT_MET 严格来说不算错误,只是正常的跳过行为。

错误枚举说明
UNKNOWN_ACTION未知的动作 ID
INVALID_SYNTAX动作行语法错误
MISSING_PARAMETER缺少必需参数
INVALID_PARAMETER参数值无效
CONDITION_NOT_MET条件不满足(正常跳过)
CHANCE_NOT_MET概率未命中(正常跳过)
EXECUTION_FAILED动作执行过程中发生异常
PLAYER_OFFLINE目标玩家不在线
ECONOMY_INSUFFICIENT经济余额不足
ITEM_SOURCE_NOT_FOUND物品来源无法解析
TEMPLATE_NOT_FOUND引用的模板不存在
java
actionService.execute(actionLines, context).whenComplete((result, ex) -> {
    if (result.hasErrors()) {
        for (ActionError error : result.getErrors()) {
            logger.warning("动作执行错误: " + error.type() + " - " + error.message());
        }
    }
});

Released under the GPL-3.0 License