跳转至

KubeJS 可操作 UI(内置 Chest GUI:1.20.1 官方方案)

原文:原创教程(ぴよまる),API 依据 KubeJS 6.1(Minecraft 1.20.1)源码 dev.latvian.mods.kubejs.gui

1.20.1 想要"能点能放"的可操作 UI,不用装任何第三方插件——KubeJS 6.1 官方内置了一套 GUI 系统:player.openChestGUI() 能打开一个自定义箱子界面(1~6 行格子),每个格子可以放物品、设按钮、绑点击回调;还有 player.openGUI()player.openInventoryGUI() 做更自由的容器菜单。

版本说明:这是 KubeJS 6.1(Minecraft 1.20.1)内置功能,开箱即用,Forge/Fabric 均可。第三方 ScreenJS 只支持 1.19.2,1.20.1 请用本方案。


1. 最简单的用法:打开一个自定义箱子界面

// server_scripts/shop_gui.js
ItemEvents.rightClicked('kubejs:shop_wand', event => {   // 右键"商店法杖"时打开 GUI
  // openChestGUI(标题, 行数(1~6), 配置回调):打开一个自定义箱子界面
  event.player.openChestGUI('我的商店', 3, gui => {   // 3 行 = 27 个格子
    // 在 (4, 1) 格子放一个"按钮":显示为钻石,点击后执行回调
    gui.button(4, 1, 'minecraft:diamond', '买钻石', click => {
      click.slot.gui.player.give('1x minecraft:diamond')   // 给玩家 1 个钻石
      click.slot.gui.player.tell('§a你买了一个钻石!')      // 提示玩家
    })
  })
})

💡 button(x, y, 物品, 名称, 回调)x 是列(0~8)、y 是行(0~行数-1);格子里显示那个物品,鼠标移上去显示名称,左键点击触发回调


2. 槽位操作(setItem / getItem / 点击绑定)

2.1 在指定格子里放物品

ItemEvents.rightClicked('kubejs:wand', event => {   // 右键法杖打开界面
  event.player.openChestGUI('展示柜', 1, gui => {   // 1 行 = 9 格
    // 用 getSlot(x, y) 拿到格子,setItem() 放物品进去
    gui.getSlot(0, 0).setItem('minecraft:diamond')        // 第 1 格放钻石
    gui.getSlot(1, 0).setItem('2x minecraft:gold_ingot')  // 第 2 格放 2 个金锭
    gui.getSlot(2, 0).setItem('minecraft:stick')          // 第 3 格放木棍
  })
})

2.2 给格子绑定"点击行为"(三种点击分别处理)

ItemEvents.rightClicked('kubejs:wand', event => {   // 右键法杖打开界面
  event.player.openChestGUI('技能书', 1, gui => {   // 1 行界面
    let slot = gui.getSlot(0, 0)                    // 拿到第 1 个格子
    slot.setItem('minecraft:book')                  // 格子里放一本书

    slot.setLeftClicked(click => {                  // 左键点击
      click.slot.gui.player.tell('你点了左键!')
    })
    slot.setRightClicked(click => {                 // 右键点击
      click.slot.gui.player.tell('你点了右键!')
    })
    slot.setShiftLeftClicked(click => {             // Shift+左键
      click.slot.gui.player.tell('你 Shift 左键了!')
    })
    slot.setMiddleClicked(click => {                // 中键点击
      click.slot.gui.player.tell('你点了中键!')
    })
  })
})

可用的点击绑定方法:

方法 触发方式
setLeftClicked(cb) 左键点击
setRightClicked(cb) 右键点击
setMiddleClicked(cb) 鼠标中键点击
setShiftLeftClicked(cb) Shift + 左键
setShiftRightClicked(cb) Shift + 右键
setDoubleClicked(cb) 双击
setSwapped(cb) 按交换键(默认 F)点击
setThrown(cb) 丢弃键点击(默认 Q)

3. 区域批量配置(slot 快速填充)

ItemEvents.rightClicked('kubejs:wand', event => {   // 右键法杖打开界面
  event.player.openChestGUI('宝石展架', 2, gui => {   // 2 行界面
    // 批量给 (0,0) 到 (8,1) 全部 18 个格子放物品
    gui.slot(0, 0, 8, 1, slot => {
      slot.setItem('minecraft:emerald')   // 每个格子都放绿宝石
      slot.setLeftClicked(click => {      // 每个格子点击都给 1 个绿宝石
        click.slot.gui.player.give('1x minecraft:emerald')
      })
    })
  })
})

4. 全局回调(任何格子点击 / 点玩家背包 / 关闭界面)

ItemEvents.rightClicked('kubejs:wand', event => {   // 右键法杖打开界面
  event.player.openChestGUI('事件演示', 2, gui => {   // 2 行界面

    // 任意一个自定义格子被点击时触发(包括没绑回调的格子)
    gui.anyClicked = click => {
      console.log('点了格子 (' + click.slot.x + ',' + click.slot.y + ')')
    }

    // 玩家点自己背包里的物品时触发
    gui.inventoryClicked = click => {
      console.log('点了背包格子')
    }

    // 界面关闭时触发
    gui.closed = () => {
      console.log('界面已关闭')
    }
  })
})

⚠️ gui.anyClicked 只在界面自己的格子上触发;玩家背包区域用 gui.inventoryClicked。想阻止默认行为可以调 click.setHandled()


5. 完整案例:迷你商店(卖东西给玩家)

// server_scripts/mini_shop.js
// 效果:右键商店法杖 → 打开 2 行商店界面,点商品格子就花钱(经验)买东西

ItemEvents.rightClicked('kubejs:shop_wand', event => {   // 监听"右键商店法杖"
  let player = event.player                              // 拿到玩家

  player.openChestGUI('迷你商店', 2, gui => {            // 2 行 = 18 格
    // 商品 1:钻石,价格 5 级经验
    gui.button(0, 0, 'minecraft:diamond', '钻石 · 5 级经验', click => {
      let p = click.slot.gui.player                      // 点击的玩家
      if (p.experienceLevel >= 5) {                      // 经验够吗?
        p.addExperienceLevels(-5)                        // 扣 5 级经验
        p.give('1x minecraft:diamond')                   // 给钻石
        p.tell('§a购买成功:钻石!')
      } else {
        p.tell('§c经验不足!需要 5 级。')
      }
    })

    // 商品 2:金苹果,价格 10 级经验
    gui.button(1, 0, 'minecraft:golden_apple', '金苹果 · 10 级经验', click => {
      let p = click.slot.gui.player
      if (p.experienceLevel >= 10) {
        p.addExperienceLevels(-10)
        p.give('1x minecraft:golden_apple')
        p.tell('§a购买成功:金苹果!')
      } else {
        p.tell('§c经验不足!需要 10 级。')
      }
    })

    // 关闭时提示
    gui.closed = () => player.tell('§7商店已关闭,欢迎下次光临!')
  })
})

6. 更自由的 openGUI / openInventoryGUI

如果箱子样式不够用,还有两个进阶入口(源码 kjs$openGUI / kjs$openInventoryGUI):

// openInventoryGUI:直接给一个物品容器(Inventory)当界面
ItemEvents.rightClicked('kubejs:bag', event => {   // 右键"袋子"物品
  let inv = event.player.persistentData.bag || { slots: [] }   // 自己的存档当容器
  event.player.openInventoryGUI(inv, '我的背包')    // 打开容器界面
})

// openGUI:完全自定义尺寸的容器菜单(宽度/高度/标题)
ItemEvents.rightClicked('kubejs:custom', event => {
  event.player.openGUI(gui => {
    gui.title = '自定义界面'        // 标题
    gui.width = 176               // 界面宽度(像素)
    gui.height = 166              // 界面高度(像素)
    gui.inventory = /* 一个 Inventory 对象 */   // 可选:绑定物品容器
  })
})

💡 openGUI 的自由度最高,适合进阶玩家;日常做商店/菜单用 openChestGUI 就够了。


7. 速查表

想做什么 写法
打开自定义箱子界面 player.openChestGUI(标题, 行数1~6, gui => {...})
放物品到格子 gui.getSlot(x, y).setItem('id')gui.getSlot(x, y).setItem('2x id')
读格子物品 gui.getSlot(x, y).getItem()
放一个按钮 gui.button(x, y, 物品, 名称, 点击回调)
左键点击 slot.setLeftClicked(cb)
右键点击 slot.setRightClicked(cb)
Shift+左键 slot.setShiftLeftClicked(cb)
中键点击 slot.setMiddleClicked(cb)
双击 slot.setDoubleClicked(cb)
批量配置区域 gui.slot(x0, y0, x1, y1, slot => {...})
任意格子点击 gui.anyClicked = click => {...}
点背包格子 gui.inventoryClicked = click => {...}
关闭界面 gui.closed = () => {...}
阻止默认行为 click.setHandled()
打开容器界面 player.openInventoryGUI(容器, 标题)
自由容器菜单 player.openGUI(gui => { gui.title/width/height = ... })
点击事件里拿玩家 click.slot.gui.player

💡 记忆口诀openChestGUI(标题, 行数, 回调) 开界面 → gui.button(x, y, 物品, 名, 回调) 放可点按钮 → gui.getSlot(x, y).setItem(...) 摆物品 → slot.setLeftClicked/setRightClicked/... 绑点击 → gui.closed 收尾;点击回调里用 click.slot.gui.player 拿玩家。


本文为 KubeJS 1.20.1 中文文档原创篇目。API 依据 KubeJS 6.1 源码 dev.latvian.mods.kubejs.gui(KubeJSGUI / KubeJSMenu / CustomChestMenu / ChestMenuData / ChestMenuSlot),1.20.1 内置无需插件。