跳到主要内容

要钥匙才能开

这一页讲怎么让玩家必须拿着特定物品才能打开宝箱。

先理解它的工作方式​

这个插件的钥匙不是虚拟货币,也不是次数。它直接检查玩家主手拿着的物品长什么样。

所以流程是这样的:

  1. 你规定"手上拿着 10 张名字带'钥匙'的纸才能开"
  2. 玩家手里拿着符合条件的纸,右键宝箱
  3. 插件检查主手物品,通过就开箱并扣掉 10 张
  4. 不通过就发一条提示,宝箱保持原样

钥匙物品本身可以由任何方式发放:商店卖、任务奖励、活动赠送,插件不管它从哪来。

只看主手

钥匙检查只读主手的物品,副手放着不算。这一点经常被玩家误解,写公告时最好说明清楚。

最简单的配置​

settings:
open_key:
deny: |-
tell "&c你需要一把钥匙才能打开"
key:
- check:
material: "tripwire_hook"
consume: true

意思是:手上拿着绊线钩就能开,开完扣掉 1 个。

三个部分:

  • deny:不满足条件时执行的脚本
  • key:可接受的钥匙列表
  • check:具体的检查条件
  • consume:是否扣除

check:能检查什么​

      - check:
material: "paper"
name: "钥匙"
lore:
- "这是个钥匙"
amount: 10
consume: true
条件怎么匹配说明
material完全相同物品材质,比如 paper、diamond
name包含就行物品名字里含有这段文字即可
lore每条都要有你写的每一条都必须能在物品描述里找到
custom_model_data完全相同模型数据,需要 1.14+
amount至少这么多需要的数量,默认 1

所有写了的条件必须同时满足。上面那个例子要求:材质是纸、名字里有"钥匙"、描述里有"这是个钥匙"、数量至少 10 个。

不需要检查的条件直接不写就行。

name 是包含匹配​

          name: "钥匙"

这样配的话,下面这些物品名都能通过:

  • 钥匙
  • 每日钥匙
  • &6黄金钥匙
  • 宝箱钥匙 x1

比较之前会去掉颜色代码,所以物品名带颜色不影响匹配。

想精确一点就把名字写全:

          name: "每日宝箱钥匙"

lore 是"每条都要有"​

这一点容易搞反。假设你这样配:

          lore:
- "限时活动"
- "不可交易"

物品的描述必须同时包含"限时活动"和"不可交易"两句才算通过。只有其中一句是不行的。

物品自己有多余的描述行不影响匹配。

amount 是最低数量​

          amount: 10

玩家手上至少要有 10 个。有 15 个也能开,扣的时候只扣 10 个。

必须是大于 0 的整数。

1.14 以下不要用 custom_model_data

低于 1.14 的服务端不支持这个属性。如果你配了,插件启动时会警告说这个条件永远不会匹配,等于把宝箱锁死了。

默认的 def.yml 里这一行是注释状态,就是这个原因。

consume:扣不扣​

        consume: true     # 扣掉(默认)
consume: false # 只检查,不扣

false 适合做"通行证"类型的钥匙:需要持有,但不会消耗。

配置多种钥匙​

key 是一个列表,可以放多个条目。玩家满足任意一个就能开箱:

settings:
open_key:
deny: |-
tell "&c你没有合适的钥匙"
key:
# 方案一:10 张普通钥匙,会扣
- check:
material: "paper"
name: "普通钥匙"
amount: 10
consume: true

# 方案二:1 个 VIP 令牌,不扣
- check:
material: "gold_ingot"
name: "VIP令牌"
consume: false

插件从上往下检查,用第一个满足条件的方案。所以把消耗少的、优先级高的放前面。

deny:拒绝时的提示​

    deny: |-
tell inline "&c钥匙不够 {{ &has_amount }} / {{ &required_amount }}"

可用的变量:

变量含义
&has_amount玩家手上有几个(空手时是 0)
&required_amount这次需要几个
&consume是否需要消耗

注意 tell inline 和 tell 的区别:用了变量就必须写 tell inline,并且变量要用 {{ }} 包起来。

不用变量的话简单写就行:

    deny: |-
tell "&c你需要一把钥匙"
required_amount 在空手时是多少

玩家空手右键时,插件没法知道他想用哪种钥匙,此时 &required_amount 取所有方案里要求数量最少的那个值。

检查和扣除的时机​

这个顺序能解释很多疑问,值得看一下:

  1. 玩家右键宝箱,第一次检查钥匙
  2. 不通过 → 执行 deny,立即把宝箱重新发给玩家,不扣钥匙
  3. 通过 → 执行 events.open 脚本和插件事件
  4. 第二次检查钥匙(因为上一步的脚本可能改了玩家手上的东西)
  5. 构建界面并打开,确认玩家真的看到了界面
  6. 再确认一次这个坐标对玩家还是可见的
  7. 全部通过 → 这时才扣钥匙,然后移除宝箱、播放动画

几个由此得出的结论:

  • 钥匙不足时宝箱不会消失。插件会立即重发一次、1 tick 后再补发一次
  • 任何一步失败都不会扣钥匙,不存在"扣了钥匙但没开箱"
  • 如果玩家在开箱瞬间把钥匙丢掉,第 5 步会检测到并取消开箱

用命令测试时的注意点​

/tsl open mychest

这个命令也会检查钥匙。测试配了钥匙的宝箱时,手上也得拿着钥匙,否则会直接触发 deny。

想跳过钥匙测试奖励配置的话,临时把 open_key 整段注释掉。

不要钥匙​

不写 settings.open_key 节点,宝箱就是直接能开的。

写了 open_key 但没有有效条件会锁死宝箱

如果 open_key 存在,但 key 下面是空的、或者所有条目都因为格式问题被跳过,插件会输出 该宝箱将拒绝开启,谁都打不开这个箱子。

注意默认的 skull_test.yml 里就有一个 key: 后面什么都不写的例子,那是测试用的。

配错了怎么发现​

启动或 /tsl reload 时,插件会逐条检查钥匙配置并输出提示:

控制台提示原因
宝箱 X 已加载 N 个钥匙条件正常,N 是实际生效的条数
open_key.key[N] 不是对象,已跳过那一条没写成 - check: 的结构
open_key.key[N].check 缺失或格式错误,已跳过少了 check 或者缩进不对
open_key.key[N].check.amount 不是整数,已跳过amount 写了非整数
open_key.key[N].check.amount 必须大于 0,已跳过amount 填了 0 或负数
open_key.key[N].check 没有可识别条件,已跳过check 下面一个有效条件都没有
配置了 custom_model_data,但当前服务端低于 1.14该条件不会匹配

序号从 0 开始,key[1] 指的是第二条。

想看每次匹配的细节就开 /tsl debug,能看到命中了第几个条件、持有多少、需要多少、扣完剩多少。

完整示例​

一个需要钥匙的每日宝箱:

title: "&6&l每日宝箱"

layout:
- '#########'
- ' 1111111 '
- '#########'

settings:
block: "TRAPPED_CHEST"
lock_inventory: true
open_key:
deny: |-
tell inline "&c需要每日钥匙 &7({{ &has_amount }}/{{ &required_amount }})"
key:
# 普通玩家:3 个钥匙
- check:
material: "tripwire_hook"
name: "每日钥匙"
amount: 3
consume: true

# VIP:持有令牌即可,不消耗
- check:
material: "nether_star"
name: "VIP令牌"
consume: false

events:
close: |-
tsl-claim

claim:
key: 1
amount: 3~5
layout: random
generator:
iron:
chance: 70
give: source
material: "iron_ingot"
amount: 3~8
gold:
chance: 30
give: source
material: "gold_ingot"
amount: 2~4

icons:
'#':
material: "GRAY_STAINED_GLASS_PANE"
name: " "

怎么给玩家发钥匙​

插件本身不负责发钥匙。常见做法:

  • 用其他插件的商店卖(比如 Malkuth)
  • 用 CDK 兑换码发放(比如 CDKLite)
  • 每日签到插件当奖励发
  • 管理员用原版 /give 命令直接发

原版命令的写法在不同版本差别很大,按你的服务端版本选:

# 1.13 ~ 1.20.4
/give <玩家> tripwire_hook{display:{Name:'{"text":"每日钥匙"}'}} 3

# 1.20.5 及以上(改成了组件格式)
/give <玩家> tripwire_hook[custom_name='{"text":"每日钥匙"}'] 3

# 1.12.2
/give <玩家> tripwire_hook 3 0 {display:{Name:"每日钥匙"}}
用命令发钥匙容易出错

原版命令对引号和格式很敏感,写错一个字符就会失败。更稳的做法是自己在游戏里做好一个钥匙物品,然后用带物品库的插件(Zaphkiel、NeigeItems、ItemsAdder 等)保存成模板来发放。

不管用哪种方式,只要物品的材质、名字、描述符合你配的 check 条件就行,插件不关心它从哪来。