Skip to content

多方块结构 ​

多方块结构就是玩家用方块搭出来的一个「机关」. 你先把形状和坐标写进配置文件; 玩家把方块摆成这个形状并与之交互 (最常见的做法是对着方块按右键) 后, 插件会逐个核对方块是否对得上, 对得上就执行你配置好的动作 (发消息, 给经验等)

每个结构对应一个文件, 放在 plugins/EmakiStructure/multiblocks/<id>.yml. 文件名就是结构 id, 两者不一致时插件会拒绝加载

定义格式 ​

yaml
version: 1                    # 当前只支持 1 (填别的会被拒绝加载)
id: "teleporter"              # 必须与文件名一致, 否则拒载 (id_mismatch)

shape:
  allow_rotation: true        # 默认 true: 玩家把整个结构转 90 度摆放也算通过
  core_block: [4, 1, 4]       # 可选: 核心方块坐标. 玩家右键它就能触发 (不写则右键任意成员方块都算)
  blocks:                     # 结构由哪些方块组成
    - pos: [4, 1, 4]          # 相对坐标, 以结构最小角为原点 (0,0,0), 不能为负
      block: "minecraft:obsidian"
    - pos: [4, 2, 4]
      block: "minecraft:ender_eye"       # 要指定方块状态就写 minecraft:...[state=value]
    - pos: [5, 1, 4]
      block: "craftengine-myns:console"  # 自定义方块写成 来源-原始id, 不能带状态段
    - pos: [6, 1, 4]
      furniture: "itemsadder:myplugin:chair"  # 家具成员; 与 block 只能二选一

trigger:
  targets: "any"              # any = 任意成员触发; specific = 只有 positions 里的方块能触发; all = 全部成员都要被点到
  positions:                  # targets 填 specific 时必填
    - [4, 1, 4]
  actions: |                  # 触发后执行的动作, 一行一条 (CoreLib 动作管道语法)
    send_message "&a传送门已激活!"
    action giveexp amount=10

cooldown:                     # 可选: 冷却, 防止玩家连点
  global: "0"                 # 所有玩家共享的冷却; 0 = 无冷却, 支持 30s / 5m 写法
  per_player: "0"             # 每个玩家各自计的冷却

condition: "permission=teleport.use"   # 可选: 触发条件, 不满足就不触发 (CoreLib 条件语法)

坐标一律是相对坐标: 以结构自身的最小角为原点 (0,0,0), 不是世界坐标. 想知道某个方块该填什么, 可以用 /ems multiblock export <id> 按选区自动生成, 直接参照生成结果填写

加载时的检查 ​

插件在读取每个文件时会逐条检查, 任何一条不通过就拒绝整个文件或跳过该成员, 并在控制台写明是哪个文件, 哪一行出了问题:

  • 每个成员必须只写 block 或 furniture 中的一个, 不能两个都写或都不写
  • 坐标必须非负, 落在结构尺寸内, 且不能重复
  • furniture 只认 itemsadder: / oraxen: / nexo: / craftengine: 这四种开头
  • block 写 minecraft: 开头时能带方块状态; 写其他来源 (自定义方块) 时不能带状态段
  • targets 填了 any / specific / all 以外的值, 或者 specific 没写 positions, 或者一个有效成员都没有 (blocks_empty), 都会拒绝整个文件
  • id 与文件名不一致, version 不是 1, 文件读取失败, 同样拒绝加载
  • 同一个 id 出现两次时, 后一个不加载 (duplicate_id)

命令 ​

  • /ems multiblock export <id> [force]: 按当前选区导出结构定义; 该 id 已存在时需加 force 才会覆盖 (already_exists)
  • /ems multiblock place <id> [朝向]: 手动把结构摆放到你站的位置 (原版方块 / 自定义方块 / 家具三类成员都会放), 放完自动开始形状检测; 最多回报 5 条失败项
  • /ems multiblock list: 列出所有已加载的定义, 以及数量统计
  • /ems multiblock validate <id>: 对现场再检查一次形状, 不通过时该实例会被标记为未完成 (verification_failed)

触发流程 ​

玩家交互后, 插件按下面的顺序逐步处理:

  1. 命中结构: 玩家右键的方块属于某个结构区域 (或点中了候选位置)
  2. 判断是否摆齐: 只检查发生过变化的方块, 不做全图扫描. 短时间内的重复变更会被合并处理 (detection.debounce), 需要推断结构位置时受 detection.max_cold_checks 的数量上限约束
  3. 条件与冷却: 先看 condition 是否满足 (整个条件组都满足才算通过), 再看冷却. 冷却优先取定义文件里的 cooldown 节, 没写就回退到 config.yml 的 cooldown.global / cooldown.per_player
  4. 发事件: 触发 MultiblockTriggerEvent (不能取消), 在正在处理这次交互的线程上发出; Folia 上就是被点方块所在区域的那个线程
  5. 执行动作: 逐行执行 trigger.actions

retrigger_on_reform 默认是 false: 结构被破坏后又重新摆好时, 它只恢复为活动状态, 不会再次触发, 这样玩家就没法反复拆了重摆刷奖励

增量检测配置要点 ​

下面这些键都在配置详解的 detection 节:

  • sweep_interval: 定期扫描的间隔, 用来补查可能漏掉的情况. 0 表示关闭; 开启时不能小于 30s. 它只扫描"进行中"的结构, 不做全图遍历
  • instance_limit: 每个定义, 每个玩家最多同时保留多少个"进行中"记录, 超了就淘汰最旧的
  • instance_ttl: 一个"进行中"记录多久没有任何变化就被清理
  • sample_recheck: 要不要对活动中的结构做低频抽样复检, 默认关闭