简体中文
GUI 系统
CoreLib 的 GUI 系统涵盖菜单模板写法, 点击处理, 以及菜单以什么方式呈现给玩家
CoreLib GUI 系统给整套插件提供菜单能力: 你只要定义好自己的 GUI 配置, 打开菜单, 记录玩家的操作状态, 拦截异常点击这些事都由 CoreLib 统一处理, 不用自己写 InventoryClickEvent 那套代码
使用 GUI 系统的模块
| 模块 | 用途 |
|---|---|
| EmakiForge | 锻造界面, 配方书 |
| EmakiStrengthen | 强化界面, 材料槽, 保护材料槽 |
| EmakiGem | 镶嵌, 提取, 开孔, 升级界面 |
| EmakiSkills | 技能界面, 触发器选择界面 |
| EmakiCooking | 蒸锅, 烤炉, 榨汁机, 发酵桶 GUI |
| EmakiAttribute | 属性点加点界面 |
| EmakiItem | 物品修复界面 |
| EmakiLevel | 等级面板, 排行榜界面 |
| EmakiStorage | 分页仓库界面 |
菜单渲染后端
plugins/EmakiCoreLib/config.yml 的 gui.backend 决定 Emaki 系列所有菜单如何呈现给玩家:
| 值 | 说明 |
|---|---|
bukkit | 默认值. 打开真实服务端容器, 无需任何前置插件 |
packet | 由 CoreLib 内置的发包虚拟菜单, 刷新不同行数时重复使用同一个窗口, 光标不会被重置; 需要额外安装 PacketEvents. 未安装时自动改回 bukkit |
auto | 安装了 PacketEvents 就用 packet, 否则用 bukkit |
默认保持 bukkit, 所以升级 CoreLib 不会改变现有菜单行为. 填了未知取值会输出一次警告, 并按 bukkit 处理
相关配置键
| 字段 | 类型 | 必填 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|---|---|
gui.backend | string | 否 | "bukkit" | bukkit / packet / auto | 菜单的显示方式, 取值见上表. 填了不认识的值就按 bukkit 处理并输出警告 |
gui.click_interval_ms | integer | 否 | 100 | ≥ 0 (0 表示不限制) | 同一个玩家两次点击菜单之间的最小间隔, 单位毫秒; 在这个间隔内的后续点击不会被菜单处理. 填小于 0 的值按 0 处理 |
默认值片段:
yaml
gui:
backend: "bukkit"
click_interval_ms: 100使用示例 (启用发包菜单, 并把点击间隔放宽到 150ms):
yaml
gui:
backend: "packet"
click_interval_ms: 150GUI 模板配置
GUI 模板就是菜单的静态定义, 描述界面的标题, 大小, 槽位布局和按钮
顶层字段
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
id | string | 是 | — | 模板的唯一标识, 模块内部靠它引用这份模板. 留空时整份模板会被判为无效 |
title | string / object | 否 | GUI | 界面标题. 支持 MiniMessage 格式字符串或 TextConfig 对象 |
gui_type | string | 否 | CHEST | 容器类型, 取值为 Bukkit InventoryType 名称. 非法值不报错地改回 CHEST; 该类型不支持自定义行数时 rows 强制为 0 |
rows | integer | 否 | 3 | 界面行数, 超出 1–6 会被限制到该区间, 对应 9–54 个槽位 |
slots | map | 否 | {} | 槽位定义, key 为槽位名称, value 为槽位配置对象. 不写时是空的, 不会报错 |
槽位配置字段
每个槽位用来定义一组格子的外观和行为:
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
key | string | 是 | — | 槽位名称, 模块内部靠它引用这个槽位 |
slots | list<integer> | 是 | — | 对应的格子索引列表 (0 起始, 从左到右, 从上到下) |
type | string | 否 | "" | 槽位类型标签, 如 input, output, button, decoration |
item | object | 否 | — | 共享物品定义, 包含 source, amount 与 components. 缺少 source 时, 可以只当成一组组件改动, 用在运行时已有的物品上 |
sounds | map | 否 | — | 点击音效配置, 按点击类型区分 |
统一物品结构
新配置和默认资源都只写嵌套结构:
yaml
item:
source: minecraft-anvil
amount: 1
components:
custom_name: '<green>确认</green>'
lore:
- '<gray>点击执行</gray>'
item_model: emaki:confirm
enchantment_glint_override: true
$unset:
- repairable
$reset:
- attribute_modifierssource接受 CoreLib 当前注册的全部 ItemSource 简写; 实际能不能用, 取决于对应的解析器有没有装上- 普通组件值表示
SET;$unset删除组件,$reset恢复该材质原型的默认组件 - 组件 ID 必须是合法的 namespaced key; 不写命名空间时补为
minecraft:, 自己写了命名空间就按写的来. 该规则同样适用于$unset/$reset列表. 未知 ID 或当前版本支持但值非法属于配置错误 - 已知但高于当前服务器版本的组件会跳过并记录警告, 不会加载高版本专用类
- 第三方来源先克隆原物品, 保留来源身份, PDC 和未知组件, 只应用当前 Paper 可安全传递的 patch
- 旧槽位
item: <source>与顶层components,display_name,lore等仍可读取, 但仅作为兼容输入; 新旧同时出现时以嵌套item为准 - 玩家真实放入的目标物, 材料和业务产物仍由会话状态决定, 不会被模板展示物品强行覆盖
旧版 GUI 物品字段自动迁移已下线
注意: 共享 gui/*.{yml,yaml} 不再在加载前自动迁移旧版 configured-item 字段. CoreLib 已移除 item.migration.configureditem 包与运行时 LegacyConfiguredItemConverter, GuiTemplateLoader 也不再挂接迁移入口. 你要让 GUI 模板中的物品定义直接使用 canonical 结构: 来源写 item.source (例如 minecraft-diamond_sword), 数量写 item.amount, 名称, Lore, 模型数据与组件写 item.components
旧字段 (material, item_source / item_sources, 标量 item, display_name, item_name, lore, custom_model_data, enchantments, item_flags, hidden_components, unbreakable 等) 不会再被转换或补齐, 也不会再产生 migration-backups/configured-item-format/ 备份. 所以升级前请手工改写, 并自行备份完整配置目录
点击类型
GUI 系统能识别这些点击类型:
| 点击类型 | sounds 键 | 说明 |
|---|---|---|
CLICK | click | 通用点击 (没有匹配到具体类型时就用它) |
LEFTCLICK | left_click | 左键点击 |
RIGHTCLICK | right_click | 右键点击 |
SHIFT_LEFTCLICK | shift_left_click | Shift + 左键 |
SHIFT_RIGHTCLICK | shift_right_click | Shift + 右键 |
MIDDLECLICK | middle_click | 中键点击 |
DOUBLECLICK | double_click | 双击 |
NUMBER_KEY | number_key | 数字键换位 |
SWAP_OFFHAND | swap_offhand | 副手交换键 (默认 F) |
DROP | drop | 丢弃键 (默认 Q) |
CONTROL_DROP | control_drop | Ctrl + 丢弃键 |
sounds 映射的键要写上表 sounds 键列的小写形式 (解析时不区分大小写); 写成枚举名 (如 LEFTCLICK) 不会命中, 会被当成未知键, 输出一条警告后忽略. 音效查找分三级: 先精确匹配当前点击类型; 未命中时按兼容映射再查一次 (SHIFT_LEFTCLICK 与 DOUBLECLICK 回退到 LEFTCLICK, SHIFT_RIGHTCLICK 回退到 RIGHTCLICK); 仍未命中才回退到 CLICK. 未注册的未知 sounds 键会输出一条 issue (如 Unknown gui sound key '...' ignored.)
完整 GUI 配置示例
强化界面示例
yaml
id: strengthen_gui
title: '<dark_gray>装备强化'
rows: 6
slots:
background:
slots: [0,1,2,3,4,5,6,7,8,9,10,11,12,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,50,51,52,53]
type: decoration
item:
source: minecraft-black_stained_glass_pane
components:
minecraft:custom_name: ' '
minecraft:tooltip_display:
hide_tooltip: true
target:
slots: [13]
type: input
item:
source: minecraft-air
components:
minecraft:custom_name: '<gray>放入目标装备'
minecraft:lore:
- '<dark_gray>将需要强化的装备放在这里'
confirm:
slots: [49]
type: button
item:
source: minecraft-anvil
components:
minecraft:custom_name: '<green>开始强化'
minecraft:lore:
- '<gray>放入装备和材料后点击'
- ''
- '<yellow>左键点击开始强化'
minecraft:enchantments:
minecraft:unbreaking: 1
minecraft:tooltip_display:
hidden_components:
- minecraft:enchantments
sounds:
left_click:
sound: minecraft:block.anvil.use
volume: 0.8
pitch: 1.0锻造界面示例
yaml
id: forge_gui
title: '<dark_gray>锻造台'
rows: 6
slots:
background:
slots: [0,1,2,3,4,5,6,7,8,9,17,18,26,27,35,36,44,45,46,47,48,49,50,51,52,53]
type: decoration
item:
source: minecraft-gray_stained_glass_pane
components:
minecraft:custom_name: ' '
blueprint_slot:
slots: [10]
type: input
item:
components:
minecraft:custom_name: '<aqua>图纸槽'
minecraft:lore:
- '<gray>放入锻造图纸'
material_slots:
slots: [11,12,13,14,15,16,19,20,21,22,23,24,25]
type: input
item:
components:
minecraft:custom_name: '<yellow>材料槽'
minecraft:lore:
- '<gray>放入锻造材料'
target_slot:
slots: [28]
type: input
item:
components:
minecraft:custom_name: '<gold>目标装备'
minecraft:lore:
- '<gray>放入需要锻造的装备'
result_preview:
slots: [34]
type: output
item:
components:
minecraft:custom_name: '<green>预览结果'
confirm:
slots: [43]
type: button
item:
source: minecraft-smithing_table
components:
minecraft:custom_name: '<green>确认锻造'
sounds:
left_click:
sound: minecraft:block.anvil.use
volume: 1.0
pitch: 1.2GUI 会话
GUI 会话用来记录玩家当前打开的界面状态. 会话由 CoreLib 自动管理, 业务模块只要通过 GuiSessionHandler 接口处理交互逻辑
会话记录的信息包括:
- 玩家正在操作哪一个配方或流程
- 哪些槽位是输入槽 (允许放入物品), 哪些槽位禁止拿取
- 点击按钮后应该调用哪个业务流程
- 关闭界面时是否需要返还输入物品
- 当前界面的临时状态数据
有了会话, 玩家就没法通过快速点击, Shift 点击, 拖拽或异常关闭复制物品, 或绕过流程
槽位索引参考
6 行界面的槽位索引布局:
text
行 1: 0 1 2 3 4 5 6 7 8
行 2: 9 10 11 12 13 14 15 16 17
行 3: 18 19 20 21 22 23 24 25 26
行 4: 27 28 29 30 31 32 33 34 35
行 5: 36 37 38 39 40 41 42 43 44
行 6: 45 46 47 48 49 50 51 52 53常用位置:
- 中心位置 (6 行):
22(第 3 行中间) 或31(第 4 行中间) - 底部中间:
49 - 四角:
0,8,45,53
修改 GUI 的建议
- 先只改显示文本: 确认语言, 颜色, 布局是否符合预期
- 再改槽位位置: 移动按钮时确认不会和输入槽, 输出槽冲突
- 最后改交互逻辑: 例如确认按钮, 返回按钮, 分页按钮
- 每次修改后测试异常操作: Shift 点击, 拖拽, 双击, 关闭界面, 背包满
MiniMessage 与颜色
GUI 文本建议统一使用 MiniMessage 格式 (一种用 <gold> 这类标签写颜色和样式的文本格式):
yaml
item:
source: minecraft-smithing_table
components:
minecraft:custom_name: '<gold>传说锻造台'
minecraft:lore:
- '<gray>放入图纸、材料和目标装备。'
- '<yellow>点击开始锻造。'
- ''
- '<dark_gray>消耗:<white>500 金币'常用 MiniMessage 标签:
| 标签 | 效果 |
|---|---|
<red> | 红色文本 |
<green> | 绿色文本 |
<gold> | 金色文本 |
<gray> | 灰色文本 |
<dark_gray> | 深灰色文本 |
<yellow> | 黄色文本 |
<aqua> | 青色文本 |
<bold> | 粗体 |
<italic> | 斜体 |
<strikethrough> | 删除线 |
<gradient:gold:yellow> | 渐变色 |
如果某个模块仍兼容传统颜色符 (&a, §b), 建议你逐步迁移到 MiniMessage, 方便统一风格