界面服务(LinView)用于创建和管理 Bukkit 容器 GUI。它将界面布局、图标和默认动作写在资源文件中,将数据查询和点击业务写在 Java 代码中。
LinView 当前只支持 Bukkit 玩家和 9 列箱子式容器,行数建议为 1 至 6。它不依赖 NMS,而是通过 Bukkit Inventory API 创建和更新界面。
LinView 将一个界面分为 View 与 Session:
.yml、.yaml 或 .json 资源文件解析出的界面定义,可以被缓存和重载。布局和图标由资源文件定义,显示的数据和点击后的操作由代码提供。
viewId 打开的界面定义。layout 与 legend 固定定位的图标或按钮。GuiRow 列表。row 或 state 条件覆盖动态模板。flowchart LR
File["gui/<viewId>.yml"] --> Parse["解析并编译布局"]
Source["注册 Source"] --> Session["创建 GuiSession"]
Parse --> Session
Session --> Render["渲染 Bukkit Inventory"]
Click["玩家点击"] --> Route["定位静态 UID 或动态 Row"]
Route --> Hook["执行 Hook"]
Hook --> Render
视图文件默认位于:
plugins/<YourPlugin>/gui/<viewId>.yml
当代码调用 lin.linView().open(player, "demo.shop") 时,LinView 会读取 gui/demo.shop.yml、编译布局、创建会话、加载动态数据源并打开 Bukkit Inventory。
资源文件 plugins/MyPlugin/gui/demo.hello.yml:
id: "demo.hello"
type: "inventory"
allowManualClose: true
rows: 1
title: "§fHello"
layout:
- "....A...."
legend:
"A":
kind: "static"
uid: "hello"
icon:
kind: "vanilla"
key: "PAPER"
name: "§a点击问候"
lore: []
action:
type: "hook"
args:
hookId: "demo.hello"
refresh: ""
dynamicAreas: []
代码侧先注册 Hook,再打开视图:
LinView view = lin.linView();
view.hook("demo.hello", ctx -> {
Player player = (Player) ctx.viewer();
player.sendMessage("§aHello!");
});
GuiSession session = view.open(player, "demo.hello");
同一个 LinView 实例管理当前插件的所有 Hook、Source 和玩家会话。建议在插件启用阶段完成注册,不要在每次点击时重复注册。
打开界面时可以初始化状态:
GuiSession session = lin.linView().open(player, "demo.shop", state -> {
state.put("page", 0);
state.put("category", "all");
});
状态可以通过 {state.page} 等占位符参与标题、图标与动作参数渲染,也可以在 Hook 中通过 ctx.state() 修改。
使用当前版本时,需要注意:
Player 作为 viewer。type 必须为 inventory,rows 必须为 1 至 6。hook、open、back、close、state 与 command。refreshArea(...) 会重新调用该区域的 Source,并只更新该区域对应的 Bukkit 槽位。overflow 支持 truncate 与 pagination;分页由状态中的页码驱动。icon.meta 中声明原版材质作为回退。reload() 与 reload(viewId) 先准备新定义,再刷新受影响的活动会话并保留状态。定义或 Source 加载失败时保留对应旧会话,其他会话继续尝试刷新,最后汇总报告错误。
讨论