简体中文
经验来源
经验来源文件写在 sources/*.yml: 里面有哪些触发器, 每条规则能按什么条件匹配, 公式里能用哪些变量, 以及防刷是怎么处理的
经验来源文件位于 plugins/EmakiLevel/sources/*.yml. 每个文件里可以放多条来源规则. 你用 trigger 把规则挂到某个 Bukkit 或 MythicMobs 事件上, 再用匹配条件挑选要给多少经验的公式
默认来源文件:
| 文件 | 默认来源 | 说明 |
|---|---|---|
combat.yml | vanilla_entity_kill | 原版实体击杀经验 |
mythicmobs.yml | mythic_mob_kill | MythicMob 击杀经验 |
block_actions.yml | mining, logging, gathering, farming | 方块破坏, 采集, 成熟作物收获 |
fishing.yml | player_fish | 钓鱼事件经验 |
crafting.yml | craft_item | 合成结果经验 |
brewing.yml | brew_complete | 炼药完成经验 |
smelting.yml | furnace_extract | 熔炉提取结果经验 |
taming.yml | entity_tame | 驯养实体经验 |
文件结构
yaml
id: "combat_sources"
enabled: true
sources:
vanilla_entity_kill:
enabled: true
type: "combat"
trigger: "entity_kill"
include_players: false
anti_abuse:
exp_cooldown_ticks: 5
ignore_near_spawner: true
spawner_scan_radius: 8
rules:
- entity_types: ["ZOMBIE", "SKELETON"]
exp_formula: "10"
- entity_types: ["WITHER", "ENDER_DRAGON"]
exp_formula: "500"顶层字段:
| 字段 | 类型 | 必填 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|---|---|
id | string | 否 | 文件名 (去掉 .yml) | — | 来源文件标识, 主要用于方便看懂配置 |
enabled | boolean | 否 | true | true / false | 这个文件的总开关. 设成 false 时整个文件都不读 |
sources | mapping | 否 | {} | — | 这个文件里的来源规则集合, 里面的键名就是来源规则的 ID |
单个来源规则字段:
| 字段 | 类型 | 必填 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|---|---|
enabled | boolean | 否 | true | true / false | 这一条来源的开关 |
type | string | 否 | main | 已加载的等级类型 ID | 获得经验的等级类型 ID |
trigger | string | 否 | "" | 见"触发器总览" | 触发器 ID. 为空时不会命中任何事件 |
include_players | boolean | 否 | false | true / false | 只有 entity_kill 会用到; 决定击杀玩家时给不给经验 |
count_result_amount | boolean | 否 | false | true / false | 当前代码会读这个键, 但不拿它算经验; 结果数量是通过公式变量 %result_amount% 用的 |
anti_abuse.ignore_player_placed_blocks | boolean | 否 | false | true / false | 只有 block_break / crop_harvest 来源会用到; 决定要不要跳过玩家自己放过的方块 |
anti_abuse.exp_cooldown_ticks | int | 否 | 0 | 负值按 0 处理 | 同一玩家在同一来源上两次发经验之间的冷却, 单位是 tick, 也就是 1/20 秒 (一个游戏刻). 发放成功后才会开始计时 |
anti_abuse.ignore_near_spawner | boolean | 否 | false | true / false | 只有 entity_kill / mythic_mob_kill 会用到; 击杀点附近有刷怪笼时跳过这条来源 |
anti_abuse.spawner_scan_radius | int | 否 | 8 | 负值按 0 处理, 实际扫描上限 16 | 配合 ignore_near_spawner 使用, 决定扫多大范围找刷怪笼 |
attribution.expire_ticks | int | 否 | 1200 | — | 只有 brew_complete 会用到; 炼药完成事件距离玩家最后一次操作炼药台超过这么多 tick 时, 跳过这条来源 |
rules[] | list<mapping> | 否 | [] | 见"规则匹配" | 匹配规则列表. 每条来源会从上往下找, 用第一条匹配上的规则 |
actions.gain | list<string> | 否 | [] | CoreLib Action 行 | 这个配置入口保留着, 但当前代码不执行它. 真正生效的获得经验动作是等级类型自己的 upgrade.actions.gain |
触发器总览
完整共享事件 ID 说明见 CoreLib 的 共享玩法事件 ID. 下表只列 EmakiLevel 经验来源常用字段
| trigger | 事件来源 | 常用匹配字段 | 公式变量 | 默认目标类型 |
|---|---|---|---|---|
entity_kill | CoreLib 共享事件; 击杀者或最近伤害玩家 | entity_types | %entity_type% | combat |
mythic_mob_kill | CoreLib 共享事件; 同次死亡中识别到的 MythicMobs 怪物 | mob_ids | %mythic_id%, %mythic_level% | combat |
block_break | CoreLib 共享事件; 玩家破坏方块 | blocks | %block_type% | mining / logging / gathering |
crop_harvest | block_break 的派生触发; 被破坏方块是已成熟 Ageable 作物 | blocks | %block_type% | farming |
player_fish | CoreLib 共享事件; 玩家钓鱼 | states | %fish_state% | fishing |
craft_item | CoreLib 共享事件; 玩家合成物品 | item_sources + matcher | %result_amount%, %result_type% | crafting |
brew_complete | CoreLib 共享事件; 归属到最近操作炼药台的玩家 | potion_types | %potion_type% | brewing |
furnace_extract | CoreLib 共享事件; 玩家从熔炉取出产物 | item_sources + matcher | %result_amount%, %result_type% | smelting |
entity_tame | CoreLib 共享事件; 玩家驯服实体 | entity_types | %entity_type% | taming |
CoreLib 还会发出 block_place 共享事件, EmakiLevel 只用它记录玩家放置过的方块位置; 把 block_place 写进来源规则的 trigger 不会产生任何经验
规则匹配
每条规则支持以下匹配字段:
| 字段 | 类型 | 必填 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|---|---|
entity_types | list<string> | 否 | [] (不限制) | Bukkit EntityType 名, 如 ZOMBIE, WOLF, ENDER_DRAGON | 匹配实体类型 |
blocks | list<string> | 否 | [] (不限制) | Bukkit Material 名, 如 STONE, WHEAT, OAK_LOG | 匹配方块 |
states | list<string> | 否 | [] (不限制) | 事件状态名, 如钓鱼的 CAUGHT_FISH | 匹配事件状态 |
potion_types | list<string> | 否 | [] (不限制) | 药水基础类型名, 如 AWKWARD, SPEED, STRENGTH | 匹配药水基础类型 |
mob_ids | list<string> | 否 | [] (不限制) | MythicMobs 内部 ID, 如 SkeletonKing | 匹配 MythicMob ID, 匹配时会把大小写统一 |
item_sources | list<string> | 否 | [] (不限制) | 合法 CoreLib ItemSource | 事件涉及的物品 (比如合成与冶炼的结果) 必须来自这里列出的来源 |
matcher | mapping | 否 | — | 见 物品匹配器 | 通用的物品匹配器, 只按组件, PDC, Lore 等跟物品来源无关的条件进一步收窄. 和同一级的 item_sources 是"都要满足"的关系 |
exp_formula | string | 否 | 0 | 表达式 | 经验公式. 返回值小于等于 0 时不会给经验 |
匹配行为:
- 同一个
trigger可以有多条来源; 事件触发时会遍历所有同 trigger 来源 - 每条来源内部按
rules顺序寻找第一条匹配规则 - 某个匹配字段为空时, 表示该字段不限制; 例如没有写
entity_types的规则可以匹配所有实体 entity_types,blocks,states,potion_types会转为大写后匹配item_sources使用 CoreLib ItemSource 识别物品来源, 不只是原版 Material
DANGER
item_sources 与 matcher 都没写的规则会匹配任意物品, 等于一条不设任何条件的规则. 规则按从上到下的顺序取第一条匹配上的, 所以这种规则一旦写在前面, 后面所有规则就永远轮不到
这种不设条件的规则一定要放在最后. 想限制物品就写 item_sources, 需要的话再加 matcher
用 matcher 按物品数据给经验
item_sources 限定物品种类, matcher 再看物品上的具体数据, 两者是"都要满足"的关系. 例如只有合成出附了魔的产物才给额外经验:
yaml
rules:
- item_sources:
- minecraft-diamond_sword
matcher:
type: component
component: enchantments
operator: exists
exp_formula: "50"
# 兜底: 普通钻石剑
- item_sources: ["minecraft-diamond_sword"]
exp_formula: "10"一句话记住匹配顺序: 规则按从上到下的顺序取第一条匹配上的, 所以条件更窄的规则要写在前面, 范围宽或不设条件的规则放在最后
WARNING
matcher 内部不能写物品源条件 (type: item_source / item_sources / source / sources 会被拒绝并告警). 完整语法见 物品匹配器
旧键 result_item_sources
旧的 rules[].result_item_sources 已改名为 item_sources, /emakilevel convert-legacy 可自动完成这一项改名 (先不带参数跑一遍看会改哪些地方, 加 confirm 真正写入并自动备份)
经验公式
经验公式使用 CoreLib 表达式引擎和 %key% 变量写法, 填在规则的 exp_formula 里
示例:
yaml
rules:
- blocks: ["DIAMOND_ORE", "DEEPSLATE_DIAMOND_ORE"]
exp_formula: "25"
- item_sources: ["minecraft-diamond_pickaxe"]
exp_formula: "40 * %result_amount%"
- mob_ids: ["ForestBoss"]
exp_formula: "300 + %mythic_level% * 20"如果公式返回 0 或负数, 插件会跳过本次经验发放
原版击杀
默认配置:
yaml
sources:
vanilla_entity_kill:
enabled: true
type: "combat"
trigger: "entity_kill"
include_players: false
anti_abuse:
exp_cooldown_ticks: 5
ignore_near_spawner: true
spawner_scan_radius: 8
rules:
- entity_types: ["ZOMBIE", "SKELETON", "SPIDER", "CREEPER"]
exp_formula: "10"
- entity_types: ["ENDERMAN", "BLAZE", "WITHER_SKELETON"]
exp_formula: "25"
- entity_types: ["WITHER", "ENDER_DRAGON"]
exp_formula: "500"行为说明:
- 击杀归属由 CoreLib 共享事件解析: 优先使用 Bukkit 记录的直接击杀者
- 如果不是直接击杀, 并且
anti_abuse.last_damager_tracking.enabled: false, EmakiLevel 会跳过本次事件 - 最近伤害归属窗口由 CoreLib
config.yml > gameplay_events.last_damager_expire_ticks控制, 默认 200 tick include_players: false时, 击杀玩家不会给经验ignore_near_spawner: true时, 会以击杀点为中心扫描spawner_scan_radius(0–16) 范围内的方块, 发现刷怪笼即跳过该来源. 半径越大扫描的方块越多, 建议保持默认 8
方块破坏与作物收获
默认挖掘来源:
yaml
sources:
mining:
enabled: true
type: "mining"
trigger: "block_break"
anti_abuse:
ignore_player_placed_blocks: true
exp_cooldown_ticks: 2
rules:
- blocks: ["STONE", "DEEPSLATE"]
exp_formula: "1"
- blocks: ["COAL_ORE", "DEEPSLATE_COAL_ORE", "IRON_ORE", "DEEPSLATE_IRON_ORE"]
exp_formula: "5"
- blocks: ["DIAMOND_ORE", "DEEPSLATE_DIAMOND_ORE", "EMERALD_ORE", "DEEPSLATE_EMERALD_ORE"]
exp_formula: "25"防刷行为:
anti_abuse.placed_block_tracking: true时, 玩家放置过的方块位置会被记录- 如果来源设置
ignore_player_placed_blocks: true, 该来源会跳过玩家放置过的方块 - 即使来源没有写
ignore_player_placed_blocks, 当anti_abuse.placed_block_exp: false时, 玩家放置过的方块也不会给破坏经验 - 记录在方块被破坏后移除; 超过
anti_abuse.placed_block_record_ttl_ticks的记录会在下一次读写时清理
成熟作物来源使用同一个破坏事件, 但只有方块数据是 Ageable 且已成熟时才触发:
yaml
sources:
farming:
enabled: true
type: "farming"
trigger: "crop_harvest"
anti_abuse:
ignore_player_placed_blocks: true
exp_cooldown_ticks: 2
rules:
- blocks: ["WHEAT", "CARROTS", "POTATOES", "BEETROOTS", "NETHER_WART"]
exp_formula: "4"一次破坏成熟作物会同时触发 block_break 和 crop_harvest 两个触发器, 两类来源都可能各自发放经验
钓鱼
yaml
sources:
player_fish:
enabled: true
type: "fishing"
trigger: "player_fish"
rules:
- states: ["CAUGHT_FISH"]
exp_formula: "10"
- states: ["CAUGHT_ENTITY"]
exp_formula: "5"%fish_state% 对应 PlayerFishEvent.State 名称. 常见状态包括 CAUGHT_FISH, CAUGHT_ENTITY, FISHING, BITE, FAILED_ATTEMPT 等; 默认只对真正钓到物品或实体给经验
合成
yaml
sources:
craft_item:
enabled: true
type: "crafting"
trigger: "craft_item"
count_result_amount: true
rules:
- item_sources:
- "minecraft-crafting_table"
- "minecraft-furnace"
exp_formula: "5 * %result_amount%"
- item_sources:
- "minecraft-diamond_pickaxe"
- "minecraft-diamond_sword"
exp_formula: "40 * %result_amount%"合成来源会读取配方结果物品并使用 CoreLib ItemSource 识别. 公式变量:
| 变量 | 说明 |
|---|---|
%result_amount% | 配方结果堆叠数量, 至少为 1 |
%result_type% | Bukkit Material 名称 |
炼药
yaml
sources:
brew_complete:
enabled: true
type: "brewing"
trigger: "brew_complete"
attribution:
expire_ticks: 1200
rules:
- potion_types: ["AWKWARD", "SPEED", "STRENGTH"]
exp_formula: "15"炼药台事件本身不直接提供玩家, CoreLib 会记录最近操作该炼药台的玩家, 并在炼药完成时把经验归属给该玩家. 来源可用 attribution.expire_ticks 设置自己的归属窗口, 默认 1200 tick; 事件距离最后一次操作超过该窗口时跳过该来源. 公式变量:
| 变量 | 说明 |
|---|---|
%potion_type% | 炼药台产物中第一个可识别药水的基础类型; 无法识别时为 UNKNOWN |
冶炼
yaml
sources:
furnace_extract:
enabled: true
type: "smelting"
trigger: "furnace_extract"
rules:
- item_sources:
- "minecraft-iron_ingot"
- "minecraft-copper_ingot"
- "minecraft-gold_ingot"
exp_formula: "3 * %result_amount%"
- item_sources: ["minecraft-netherite_scrap"]
exp_formula: "20 * %result_amount%"公式变量:
| 变量 | 说明 |
|---|---|
%result_amount% | 玩家从熔炉中取出的物品数量 |
%result_type% | Bukkit Material 名称 |
驯养
yaml
sources:
entity_tame:
enabled: true
type: "taming"
trigger: "entity_tame"
rules:
- entity_types: ["WOLF", "CAT", "HORSE", "PARROT"]
exp_formula: "20"只有驯养者是玩家时才会发放经验. 公式变量:
| 变量 | 说明 |
|---|---|
%entity_type% | 被驯养实体的 Bukkit EntityType |
自定义来源示例
新增一个钓到宝藏时给主等级经验的来源:
yaml
id: "treasure_sources"
enabled: true
sources:
fishing_treasure_main:
enabled: true
type: "main"
trigger: "player_fish"
rules:
- states: ["CAUGHT_FISH"]
exp_formula: "2"新增一个所有原木都给砍伐经验的来源:
yaml
id: "custom_logging"
enabled: true
sources:
all_logs:
enabled: true
type: "logging"
trigger: "block_break"
anti_abuse:
ignore_player_placed_blocks: true
rules:
- blocks:
- "OAK_LOG"
- "BIRCH_LOG"
- "SPRUCE_LOG"
- "JUNGLE_LOG"
- "ACACIA_LOG"
- "DARK_OAK_LOG"
- "MANGROVE_LOG"
- "CHERRY_LOG"
exp_formula: "5"新增一个所有非玩家实体击杀都给少量主等级经验的来源:
yaml
id: "main_kill_bonus"
enabled: true
sources:
main_entity_kill_bonus:
enabled: true
type: "main"
trigger: "entity_kill"
include_players: false
rules:
- exp_formula: "1"最后一条规则没有写 entity_types, 因此会匹配所有实体