Skip to content

常见问题与边缘情况

遇到报错 / 行为不符合预期时,先翻这一页。

语法错误

错误原因解决
YAML 解析失败缩进不正确检查空格,不要混用 Tab
字符串未闭合引号不匹配确保引号成对
变量未定义拼写错误或顺序错误检查变量名,先定义后使用
mapping values are not allowed here槽位定义中的冒号被 YAML 当成映射分隔符见下方 引号嵌套规则
if 块内代码不执行使用了单行 if 语法见下方 流程控制必须多行

槽位定义的 YAML 引号嵌套规则

当槽位定义中的 lorename 等参数包含冒号 : 时,YAML 会把它当成映射分隔符,导致解析失败。

错误示例

yaml
slots:
  # ✗ lore 中的冒号导致 YAML 解析失败
: display(id=信息, material=BOOK, name="&e信息", lore="&7状态: 待机|&7等级: 1")
  #                                                          ↑ 这里被当成映射分隔符

正确写法

yaml
slots:
  # ✓ 外层单引号,内层字符串用双引号,表达式内字符串用两个单引号转义
  '信': 'display(id=信息, material=BOOK, name="&e信息", lore="&7状态: 待机|&7等级: 1")'

  # ✓ 外层双引号,内层用单引号
  '火': "button(id=开始, material=MAGMA_CREAM, name='&c&l点火', lore='&7点击开始|&7冷却: 10秒')"

  # ✓ match 表达式里需要字符串字面量时,用两个单引号 '' 转义
  'A': 'input(id=材料1, match="lore.contains(''丹材'')", placeholder=STAINED_GLASS_PANE:12:&8丹材)'

规则总结

外层引号内层字符串表达式内字符串
单引号 '...'双引号 "..."两个单引号 ''
双引号 "..."单引号 '...'单引号 '...'

中文槽位键(如 )也建议用单引号包裹,避免部分 YAML 解析器的兼容问题。

流程控制必须使用多行格式

IM 脚本引擎不支持单行流程控制,所有 ifforwhile(注意 while 本身未实现)都必须换行。

yaml
variables: |
  # ✗ 单行 if 不会执行!
  if @input.filled { 数量 += 1 }
  if a == 1 { x = 10 }

  # ✓ 必须多行
  if @input.filled {
    数量 += 1
  }

  if a == 1 {
    x = 10
  }

  # ✓ else if 也必须多行
  if a == 1 {
    x = 10
  } else if a == 2 {
    x = 20
  } else {
    x = 30
  }

实测:if 条件 { 变量 = 值 } 这种单行写法会导致块内代码不会执行,也不报错。

空值处理

# ✗ 直接使用可能为空的值
攻击力 = @input.attr("攻击力")       # 没有此属性时返回 0(或 null,视实现)

# ✓ 使用默认值
攻击力 = ifnull(@input.attr("攻击力"), 0)

# ✓ 先判断槽位是否有物品
if @input.filled {
  // 安全使用 @input
}

类型转换

# 字符串拼接
消息 = "等级: " + 等级                # ✓

# 数值计算
总和 = a + b                          # ✓ 确保 a 和 b 都是数字

# 布尔判断
if 等级 >= 5                          # ✓
if "等级" >= 5                        # ✗ 字符串被当字面量比较

lore.replace 常见问题

yaml
# 问题:变量没有替换
# ✗ 两参数写法会被当作模板语法
装备.lore.replace("等级: {}", "等级: {}")

# ✓ 写法 1:三参数
装备.lore.replace("等级", "{旧}", "{新}")

# ✓ 写法 2:模板语法用 {_} 占位
装备.lore.replace("等级: {_}", "等级: {}")

详见 Lore 动作

作用域问题

yaml
# for 仅支持数值范围,不支持列表遍历
# 累加槽位组属性,用 sum_attr 而不是手动循环:
total = sum_attr(@food, "攻击力")
effect.message("总计: {total}")

# for 循环外定义的变量,块内修改在外部可见
count = 0
for i in 1..5 {
  count += 1
}
effect.message("计数: {count}")       # 输出 5

预览脚本有独立的作用域陷阱,见 预览模式

GUI 会话与物品安全

物品归还机制

场景处理方式状态
玩家正常关闭 GUI直接归还到背包
GUI 进入后台模式超时在线时归还,离线时保存到文件
玩家下线(后台模式)保存到文件,上线后恢复会话
玩家下线(非后台模式)尝试归还,失败则保存到文件
服务器正常关闭 (stop)保存所有有物品的会话到文件
服务器崩溃(kill -9⚠️ 物品可能丢失未处理

离线会话存储

  • 位置:plugins/ItemMaster/offline-sessions/{玩家UUID}.yml
  • 内容:GUI ID、所有槽位物品(Base64 序列化)、变量快照、Toggle 状态、锁定槽位列表、保存时间戳
  • 过期:使用 session_timeout;非后台模式保存时默认设 1 小时过期;-1 永不过期

服务器崩溃

  • onDisable 不会被调用,内存中的物品丢失。
  • 缓解:重要物品先 vault.store 存到物品库。

物品序列化失败

使用 BukkitObjectOutputStream,以下情况可能失败:

  • 模组物品(非原版 Minecraft 物品)
  • 跨 MC 版本不兼容(1.12 保存 → 1.20 读取)
  • 特殊 NBT 数据(某些插件的自定义序列化器未注册)

原版物品和大多数插件物品都能正常序列化。

BungeeCord / Velocity 跨服

  • 会话仅存在于当前服务器。
  • 玩家切服触发正常下线流程,物品会被保存到当前服的离线会话。
  • 不支持跨服会话同步(已在更新计划中)。
  • 跨服传物品用 Vault 物品存储 + 数据库 / Redis 自行同步 ID。

详见 会话与物品安全

TQ Minecraft Server Plugin Docs