实战案例
5 个可直接投产的完整配方,覆盖最常见的物品操作玩法。所有示例放在 plugins/ItemMaster/recipes/ 下,文件名即配方 ID。
装备强化系统
多阶段强化,包含成功率递减、失败惩罚、满级标记。
yaml
# recipes/enhance.yml
title: "&6装备强化"
rows: 6
layout: |
XXXXXXXXX
X...I...X
X...M...X
X...P...X
X.......X
XXXBXDXXX
slots:
X: decoration(id=边框, material=BLACK_STAINED_GLASS_PANE, name=" ")
I: 'input(id=input, match="lore.contains(''可强化'') && !nbt.has(''MaxEnhance'')", placeholder=GRAY_STAINED_GLASS_PANE:"&7请放入可强化的装备")'
M: 'material(id=material, match="type.is(DIAMOND)", amount=1, placeholder=DIAMOND:"&b强化石")'
P: preview(id=preview, source="@input", script=preview_script)
B: 'button(id=confirm, material=LIME_WOOL, name="&a确认强化", lore="&7当前等级: {当前等级}|&7成功率: {成功率}%|&7消耗金币: {消耗金币}||&e点击开始强化")'
D: 'display(id=说明, material=BOOK, name="&e强化说明", lore="&7强化可以提升装备属性|&7等级越高成功率越低|&7失败有概率损坏装备")'
target: input
variables: |
当前等级 = @input.counter("强化等级")
最大等级 = 10
成功率 = max(10, 100 - 当前等级 * 8)
消耗金币 = (当前等级 + 1) * 500
目标等级 = 当前等级 + 1
conditions: |
require @input.filled : "&c请放入装备"
require @material.filled : "&c请放入强化石"
require 当前等级 < 最大等级 : "&c装备已达到最大等级"
require money >= 消耗金币 : "&c金币不足,需要{消耗金币}"
scripts:
preview_script: |
目标等级 = 当前等级 + 1
lore.setCounter("强化等级", 目标等级, 最大等级)
lore.attr("攻击力", "+5")
execute: |
装备 = @input
item.take(@material, 1)
money.take(消耗金币)
chance 成功率 {
effect.sound("ENTITY_PLAYER_LEVELUP")
effect.title("&a强化成功!", "&7等级提升至 +{目标等级}")
装备.lore.setCounter("强化等级", 目标等级, 最大等级)
装备.lore.attr("攻击力", "+5")
装备.name.suffix(" &6+{目标等级}")
if 目标等级 == 最大等级 {
装备.nbt.set("MaxEnhance", true)
effect.message("&6恭喜!装备已达到满级!")
}
slot.set("input", 装备)
} fail {
effect.sound("ENTITY_VILLAGER_NO")
chance 30 {
if 当前等级 > 0 {
新等级 = 当前等级 - 1
装备.lore.setCounter("强化等级", 新等级, 最大等级)
effect.title("&c强化失败", "&7等级降低至 +{新等级}")
slot.set("input", 装备)
} else {
effect.title("&c强化失败", "&7装备等级不变")
}
} fail {
effect.title("&c强化失败", "&7装备等级不变")
}
}
effect.refresh()要点:
@input.counter("强化等级")读取强化等级: 3/10这种格式的当前值。- 改物品前
装备 = @input,结束前slot.set("input", 装备)回写。 - 预览脚本只修改 lore / name,不做任何真实副作用。
属性洗练系统
用 6 个 Toggle 锁定属性、洗练未锁定的部分,每锁定一个额外加费。
yaml
# recipes/reforge.yml
title: "&d属性洗练"
rows: 6
layout: |
XXXXXXXXX
X..1I2..X
X..3.4..X
X..5.6..X
X.......X
XXXBXMXXX
slots:
X: decoration(id=边框, material=PURPLE_STAINED_GLASS_PANE, name=" ")
I: 'input(id=input, match="lore.contains(''可洗练'')", placeholder=GRAY_STAINED_GLASS_PANE:"&7请放入可洗练的装备")'
"1": toggle(id=锁1, toggleid=lock1, on=LIME_DYE, off=GRAY_DYE)
"2": toggle(id=锁2, toggleid=lock2, on=LIME_DYE, off=GRAY_DYE)
"3": toggle(id=锁3, toggleid=lock3, on=LIME_DYE, off=GRAY_DYE)
"4": toggle(id=锁4, toggleid=lock4, on=LIME_DYE, off=GRAY_DYE)
"5": toggle(id=锁5, toggleid=lock5, on=LIME_DYE, off=GRAY_DYE)
"6": toggle(id=锁6, toggleid=lock6, on=LIME_DYE, off=GRAY_DYE)
B: 'button(id=confirm, material=ENCHANTED_BOOK, name="&d开始洗练", lore="&7锁定数量: {锁定数量}|&7消耗金币: {消耗金币}||&d点击洗练属性")'
M: 'material(id=material, match="type.is(AMETHYST_SHARD)", placeholder=AMETHYST_SHARD:"&d洗练石")'
target: input
variables: |
锁定数量 = count_on(@lock1, @lock2, @lock3, @lock4, @lock5, @lock6)
锁定费用 = 锁定数量 * 100
基础费用 = 500
消耗金币 = 基础费用 + 锁定费用
攻击力池 = [10, 20, 30, 50, 80]
防御力池 = [5, 10, 15, 25, 40]
生命池 = [50, 100, 200, 300, 500]
conditions: |
require @input.filled : "&c请放入装备"
require @material.filled : "&c请放入洗练石"
require money >= 消耗金币 : "&c金币不足"
execute: |
装备 = @input
item.take(@material, 1)
money.take(消耗金币)
effect.sound("BLOCK_ENCHANTMENT_TABLE_USE")
if !@lock1.on {
新攻击 = list_get(攻击力池, rand(list_size(攻击力池) - 1))
装备.lore.setAttr("攻击力", 新攻击)
}
if !@lock2.on {
新防御 = list_get(防御力池, rand(list_size(防御力池) - 1))
装备.lore.setAttr("防御力", 新防御)
}
if !@lock3.on {
新生命 = list_get(生命池, rand(list_size(生命池) - 1))
装备.lore.setAttr("生命值", 新生命)
}
slot.set("input", 装备)
effect.title("&d洗练完成", "&7属性已刷新")
effect.refresh()要点:count_on(@lock1, ...) 统计 Toggle 开启个数;@lockN.on 是布尔值。
装备吞噬系统
主装备 + 最多 8 件饲料装备,累加饲料的属性到主装备。
yaml
# recipes/devour.yml
title: "&c装备吞噬"
rows: 6
layout: |
XXXXXXXXX
X..FFF..X
X..FIF..X
X..FFF..X
X.......X
XXXXBXXXX
slots:
X: decoration(id=边框, material=RED_STAINED_GLASS_PANE, name=" ")
I: 'input(id=input, match="lore.contains(''可吞噬'')", placeholder=GRAY_STAINED_GLASS_PANE:"&7放入主装备")'
F: 'input(id=food, multiple=true, match="lore.contains(''可被吞噬'')", placeholder=BARRIER:"&7放入饲料装备")'
B: 'button(id=confirm, material=WITHER_SKELETON_SKULL, name="&c开始吞噬", lore="&7饲料数量: {饲料数量}|&7获得攻击: +{总攻击力}|&7获得防御: +{总防御力}|&7当前次数: {当前次数}/{最大次数}||&c点击吞噬")'
target: input
variables: |
饲料数量 = count_filled(@food)
总攻击力 = sum_attr(@food, "攻击力")
总防御力 = sum_attr(@food, "防御力")
当前次数 = @input.counter("吞噬次数")
最大次数 = @input.counterMax("吞噬次数")
conditions: |
require @input.filled : "&c请放入主装备"
require 饲料数量 > 0 : "&c请放入至少一件饲料装备"
require 当前次数 < 最大次数 : "&c吞噬次数已达上限"
execute: |
装备 = @input
effect.sound("ENTITY_WITHER_SPAWN", 0.5, 1.5)
if 总攻击力 > 0 {
装备.lore.attr("攻击力", "+" + 总攻击力)
}
if 总防御力 > 0 {
装备.lore.attr("防御力", "+" + 总防御力)
}
新次数 = 当前次数 + 饲料数量
if 新次数 > 最大次数 {
新次数 = 最大次数
}
装备.lore.setCounter("吞噬次数", 新次数, 最大次数)
slot.set("input", 装备)
slot.clear("food")
effect.title("&c吞噬完成", "&7获得 +{总攻击力} 攻击, +{总防御力} 防御")
effect.refresh()要点:
multiple=true让槽位组@food接受任意数量的物品。sum_attr(@food, "属性名")自动遍历组内每一件。slot.clear("food")一次清空整组槽位。
装备锻造系统
3×3 材料网格 + 配方匹配,生成结果物品。
yaml
# recipes/forge.yml
title: "&e装备锻造"
rows: 6
layout: |
XXXXXXXXX
X.123...X
X.456.O.X
X.789...X
X.......X
XXXXBXXXX
slots:
X: decoration(id=边框, material=ORANGE_STAINED_GLASS_PANE, name=" ")
"1": 'input(id=mat1, placeholder=LIGHT_GRAY_STAINED_GLASS_PANE:"&7材料槽")'
"2": 'input(id=mat2, placeholder=LIGHT_GRAY_STAINED_GLASS_PANE:"&7材料槽")'
"3": 'input(id=mat3, placeholder=LIGHT_GRAY_STAINED_GLASS_PANE:"&7材料槽")'
"4": 'input(id=mat4, placeholder=LIGHT_GRAY_STAINED_GLASS_PANE:"&7材料槽")'
"5": 'input(id=mat5, placeholder=LIGHT_GRAY_STAINED_GLASS_PANE:"&7材料槽")'
"6": 'input(id=mat6, placeholder=LIGHT_GRAY_STAINED_GLASS_PANE:"&7材料槽")'
"7": 'input(id=mat7, placeholder=LIGHT_GRAY_STAINED_GLASS_PANE:"&7材料槽")'
"8": 'input(id=mat8, placeholder=LIGHT_GRAY_STAINED_GLASS_PANE:"&7材料槽")'
"9": 'input(id=mat9, placeholder=LIGHT_GRAY_STAINED_GLASS_PANE:"&7材料槽")'
O: output(id=output)
B: 'button(id=confirm, material=ANVIL, name="&e开始锻造", lore="&7匹配配方: {配方名称}||&e点击锻造")'
recipes:
钻石剑:
pattern:
- "_ DIAMOND _"
- "_ DIAMOND _"
- "_ STICK _"
result:
material: DIAMOND_SWORD
name: "&b锻造钻石剑"
lore:
- "&7锻造者: {player.name}"
- "&7攻击力: +15"
- "&7可强化"
钻石胸甲:
pattern:
- "DIAMOND _ DIAMOND"
- "DIAMOND DIAMOND DIAMOND"
- "DIAMOND DIAMOND DIAMOND"
result:
material: DIAMOND_CHESTPLATE
name: "&b锻造钻石胸甲"
lore:
- "&7锻造者: {player.name}"
- "&7防御力: +20"
variables: |
匹配配方 = match_recipe(@recipes, @mat1, @mat2, @mat3, @mat4, @mat5, @mat6, @mat7, @mat8, @mat9)
配方名称 = 匹配配方 != null ? 匹配配方.id : "无"
conditions: |
require 匹配配方 != null : "&c未匹配到任何配方"
execute: |
effect.sound("BLOCK_ANVIL_USE")
result = 匹配配方.result()
item.clear(@mat1); item.clear(@mat2); item.clear(@mat3)
item.clear(@mat4); item.clear(@mat5); item.clear(@mat6)
item.clear(@mat7); item.clear(@mat8); item.clear(@mat9)
slot.set("output", result)
effect.title("&e锻造成功", "&7获得 {匹配配方.id}")详见 配方系统。
宝石镶嵌系统
在装备的孔位里镶嵌宝石,用 NBT 记录每个孔位的状态以便拆卸。
yaml
# recipes/gem_socket.yml
title: "&b宝石镶嵌"
rows: 6
layout: |
XXXXXXXXX
X...I...X
X.1.2.3.X
X...G...X
X.......X
XXXXBXXXX
slots:
X: decoration(id=边框, material=LIGHT_BLUE_STAINED_GLASS_PANE, name=" ")
I: 'input(id=input, match="lore.regex(''孔位[123]: .*'')", placeholder=GRAY_STAINED_GLASS_PANE:"&7放入装备")'
"1": 'display(id=孔位1, material=DIAMOND, name="&b孔位1: {孔位1状态}")'
"2": 'display(id=孔位2, material=EMERALD, name="&a孔位2: {孔位2状态}")'
"3": 'display(id=孔位3, material=REDSTONE, name="&c孔位3: {孔位3状态}")'
G: 'input(id=gem, match="lore.contains(''宝石'')", placeholder=GRAY_STAINED_GLASS_PANE:"&7放入宝石")'
B: 'button(id=confirm, material=ENCHANTING_TABLE, name="&b镶嵌宝石", lore="&7将宝石镶嵌到空闲孔位||&b点击镶嵌")'
target: input
variables: |
孔位1内容 = @input.text("孔位1")
孔位2内容 = @input.text("孔位2")
孔位3内容 = @input.text("孔位3")
孔位1状态 = 孔位1内容 == "空" ? "&7空" : "&a" + 孔位1内容
孔位2状态 = 孔位2内容 == "空" ? "&7空" : "&a" + 孔位2内容
孔位3状态 = 孔位3内容 == "空" ? "&7空" : "&a" + 孔位3内容
宝石名称 = @gem.text("宝石类型")
宝石属性 = @gem.attr("属性加成")
conditions: |
require @input.filled : "&c请放入装备"
require @gem.filled : "&c请放入宝石"
execute: |
装备 = @input
目标孔位 = 0
if 孔位1内容 == "空" {
目标孔位 = 1
} else if 孔位2内容 == "空" {
目标孔位 = 2
} else if 孔位3内容 == "空" {
目标孔位 = 3
}
require 目标孔位 > 0 : "&c没有空闲孔位"
effect.sound("BLOCK_BEACON_ACTIVATE")
装备.lore.setValue("孔位" + 目标孔位, 宝石名称)
if 宝石属性 > 0 {
装备.lore.attr("属性加成", "+" + 宝石属性)
}
装备.nbt.set("Gem.Slot" + 目标孔位, 宝石名称)
装备.nbt.set("Gem.Attr" + 目标孔位, 宝石属性)
slot.set("input", 装备)
item.clear(@gem)
effect.title("&b镶嵌成功", "&7{宝石名称} → 孔位{目标孔位}")
effect.refresh()要点:
@input.text("孔位1")按 lore 行里的"字段名: 值"格式读第二段。- 用 NBT 记录每个孔位的原始宝石和属性,方便将来写拆卸功能时还原。
转盘抽奖
环形动画 + 随机停位 + 奖品发放,详细动画节拍见 delay 与 GUI 动作。
核心思路:
- 用
output槽位作为环形展示位(s1–s8),中间result显示最终奖品。 slot.lock+gui.lock锁死动画期间的点击和关闭。- 快速阶段
delay(2),减速阶段delay(5)、delay(7)、delay(10)… - 停止时只
slot.unlock("result,spin")——其他槽位保持锁定,关闭 GUI 时不会归还动画色块。 - 随机停位用
if 目标 == N { ... }块,每块内完成剩余步数 + 奖品发放 + 解锁的完整链路。