Skip to content

实战案例

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 动作

核心思路:

  1. output 槽位作为环形展示位(s1s8),中间 result 显示最终奖品。
  2. slot.lock + gui.lock 锁死动画期间的点击和关闭。
  3. 快速阶段 delay(2),减速阶段 delay(5)delay(7)delay(10)
  4. 停止时只 slot.unlock("result,spin")——其他槽位保持锁定,关闭 GUI 时不会归还动画色块。
  5. 随机停位用 if 目标 == N { ... } 块,每块内完成剩余步数 + 奖品发放 + 解锁的完整链路。

TQ Minecraft Server Plugin Docs