跳到主要内容

GUI

在网页面板中构建的物品栏菜单:布局、物品、点击动作、存储和排行榜。

免费v0.20菜单与视觉

概述​

GUI 将单个 TypeWriter 条目 Open GUI 变成一个完整的物品栏菜单。你选择容器类型(箱子、铁砧、商人窗口、成书等),用 MiniMessage 写好标题,然后把内容描述为一棵存放在该条目 layoutPool 中的布局树。每个布局会放置若干物品:材质、名称、lore,以及玩家点击它时会发生什么。

一切都在网页面板中编辑:无需手写任何菜单文件。菜单的打开方式与其他动作一样,可以来自任务步骤、NPC 对话、命令事件或另一个菜单。点击可以运行控制台命令、触发其他条目并修改 fact,因此菜单只是驱动你的 TypeWriter 页面的又一种方式。

GUI 也是其他 BTC 菜单扩展的基础。Shops 和 Quest Codex 并不自带窗口:它们在 open_gui 布局中放置标记物品,再由扩展用商品或任务来填充这些标记。

功能​

  • 十种布局 — simple、flex、paginated、scrollable、frame、composite、book、merchant、storage 和 leaderboard。
  • 24 种容器类型 — 9 到 54 格的箱子尺寸,以及铁砧、附魔台、锻造台、切石机、砂轮、织布机、制图台、商人、书、漏斗、各类熔炉等。
  • 处处支持 MiniMessage — 标题、物品名称和 lore 中可使用颜色、渐变和 PlaceholderAPI 占位符。
  • 按点击类型设置点击动作 — 左键、右键、Shift、中键、双击、数字键、丢弃和副手交换,每种都有各自的命令和触发器。
  • 槽位权限 — 用 viewPermission 隐藏槽位,或用 clickPermission 让槽位可见但无法点击。
  • 槽位重复 — 用 count、direction、gap 和 repeatY 填满一行或一块区域,无需复制物品。
  • 视图与标签页 — 一个菜单外壳、多个界面,带有面包屑标题和会高亮的标签页。
  • 持久存储 — 按玩家或按组保存物品的槽位,支持配额、占位符以及可选的关闭时掉落。
  • 排行榜 — 根据一个或多个 fact 对玩家、世界或组进行排名(包括离线玩家),也可以通过 source 字段显示其他扩展提供的行(例如 Dungeon 的统计)。
  • 扩展物品栏 — 把玩家自己的物品栏变成额外的四行菜单,形成十行的画布。

安装​

  1. 在 Paper 或 Folia 服务器上安装 TypeWriter。必须存在 TypeWriter 本来就需要的 PacketEvents。
  2. 从 GUI 的 GitHub releases 下载 JAR(即上方摘要面板中的按钮)。
  3. 将其放入 plugins/Typewriter/extensions/,然后重启服务器。
  4. 可选:如果你的标题使用 <image> 或 <shift> 标签来绘制自定义背景,请安装 CraftEngine。

请在依赖 GUI 的扩展(如 Shops 和 Quest Codex)之前先安装 GUI。

网页编辑器

公开发布的 GUI 版本不包含独立的菜单编辑器及其网页服务器:菜单在 TypeWriter 网页面板中编辑。该版本只附带一项启动检查,它会读取你已发布的 open_gui 条目,并在控制台中报告有问题的菜单(参见“故障排查”)。

快速上手​

构建一个包含三个按钮的小菜单:

  1. 在网页面板中打开一个 sequence 页面,添加一个 Open GUI 条目,并命名为 main_menu。
  2. 将 guiType 设为 CUSTOM,size 设为 SIZE_27,title 设为 <gold>Main menu。
  3. 在 layoutPool 中添加一个类型为 simple 的布局,给它设置 id 为 main,然后在 mainLayoutId 中输入 main。
  4. 在该布局的 items 中,在 x 为 4、y 为 1 的位置添加一个物品。在 item 中选择 DIAMOND,将 displayName 设为 <aqua>Rewards,并添加一行 lore:<gray>Click to claim。
  5. 在 interactionList 中添加一个 type 为 LEFT_CLICK 的交互。在 commands 中添加一条控制台命令,例如 give %player% diamond 1,或在 triggers 中链接一个条目。开启 closeMenu 可在点击后关闭菜单。
  6. 再添加第二个 simple 物品,设置 count 为 9、direction 为 right,并选用灰色染色玻璃板,绘制出一行边框。将其 displayName 设为一个空格。
  7. 将该 Open GUI 条目链接到能触发它的东西,例如某个对话选项的触发器或某个命令事件,然后 Publish(发布)。
从简单开始

在添加 frame、scrollable 或 paginated 图层之前,先让单个 simple 布局在游戏中正常工作。每个布局都通过其 id 来寻址,所以当菜单打开后是空的时,首先要检查的就是 mainLayoutId 是否输入错误。

工作原理​

动作触发时,扩展会为该玩家构建布局树(此时才会评估条件和权限),注册一个菜单会话并显示物品栏。每次点击都会根据该位置上的槽位来解析,然后运行对应的交互。会话会记住之前的菜单,因此 gui:back 会返回玩家来时的菜单。

菜单​

容器类型​

guiType 用于选择窗口。CUSTOM 是一个普通的类箱子物品栏,其高度通过 size 选择。size 只对 CUSTOM 生效,默认是六行;其他类型使用其窗口的原版尺寸。

guiType窗口
CUSTOM, CHEST, ENDER_CHEST, BARREL, SHULKER_BOX箱子式网格。对于 CUSTOM,size 可为 SIZE_9、SIZE_18、SIZE_27、SIZE_36、SIZE_45 或 SIZE_54。
HOPPER, DISPENSER, DROPPER小型固定尺寸容器。
FURNACE, BLAST_FURNACE, SMOKER, BREWING_STAND, BEACON机器窗口。
CRAFTING_TABLE, ENCHANTING_TABLE, ANVIL, SMITHING_TABLE, GRINDSTONE, LOOM, CARTOGRAPHY_TABLE, STONECUTTER原版工作站。没有布局时,它们的行为与原版界面相同;GUI 只负责打开和关闭。
MERCHANT, VILLAGER_TRADE村民交易窗口,由 merchant 布局填充。
BOOK一本成书,由 book 布局填充。

布局​

每个布局都是 layoutPool 中一个具名的条目。mainLayoutId 中指定的那个是根布局;其他布局则通过引用来到达(composite 的子项、scrollable 的 innerId、frame 的 layoutId)。

布局适用场景关键字段
simple位于 x/y 位置的固定按钮和装饰。items
flex自动按行排列的物品。justifyContent (START, CENTER, END, SPACE_BETWEEN), alignItems, wrap, virtualHeight
paginated分成多页的长列表。itemsPerPage, slots, items, navigationButtons (NEXT, PREVIOUS, BACK, INDICATOR)
scrollable比窗口更高或更宽的内容。innerId, virtualWidth, virtualHeight, buttons (direction, step), showDefaultButtons, defaultStep
frame多个相互独立的矩形,例如标签页、内容和页脚。frames (id, x, y, width, height, layoutId)
composite叠放图层:背景、内容、按钮。children(布局 id,后面的子项绘制在上层)
book成书的各页。pages (MiniMessage)
merchant使用自定义物品的村民交易。trades (result, costOne, costTwo, maxUses, criteria)
storage由 GUI Storage artifact 支撑的持久槽位。entry, groupKey, slots
leaderboard带分页的排名行,来自 fact 或其他扩展的 source。leaderboard, x, y, width, height, previousButton, nextButton

book 或 merchant 布局只能作为主布局使用,并且 guiType 会被覆盖为对应的窗口。只要 showDefaultButtons 处于开启状态(默认),scrollable 布局就会获得默认箭头:每个在 buttons 中没有条目的方向各有一个,参见 布局、框架与槽位。

各个布局的详细讲解请参见布局、框架与槽位。

物品与槽位​

布局中的每个物品都是一个槽位描述,字段相同:

字段作用
item要显示的物品。留空时,槽位会显示玩家主手所持的物品。
displayName, lore支持 PlaceholderAPI 的 MiniMessage 文本。名称默认是正体;如果想要斜体,请添加 <italic>。空的 displayName 会保留物品原本的名称,而不是用空名称替换它。
x, y列为 0 到 8,行从顶部的 0 开始。
rollPerSlot用于在多个槽位中重复且 item 为随机的物品:关闭(默认)时只抽取一次,所有槽位显示同一结果;开启时,每个槽位在菜单打开时各自抽取。菜单保持打开期间结果不变,除非开启了 liveItem。
liveItem关闭(默认):物品在菜单打开时抽取,并在整个会话中保持;刷新时只有名称和说明会更新。开启:每次刷新都会重新计算该物品,因此随机物品每次都会重新抽取。开启 rollPerSlot 时,每个重复的槽位在每次刷新时各自抽取;否则所有重复槽位每次刷新共用一次抽取。空名称仍会被忽略。
count, direction, gap, repeatY槽位重复,见下文。
criteria对不满足条件的玩家不绘制该槽位。
viewPermission看到该槽位所需的权限。
clickPermission使用该槽位所需的权限;没有该权限时,槽位会被绘制,但无法点击。
allowPickup, isGhost物品是否可以从菜单中拿出。两者默认都关闭;幽灵物品(ghost)可以被点击,但绝不能被移动或复制。
cooldownTicks同一个槽位在可再次点击之前的 tick 数。
interactionList, triggers, modifiers点击会触发什么。
input点击时打开文本输入对话框。
storageId将该槽位变成来自 storagePool 的持久存储槽位。
buttonType, buttonPrefix将该槽位标记为由另一个扩展提供的按钮。
animation菜单打开时,在以毫秒为单位的时长内把槽位移动到目标位置。

槽位重复。 count 会沿着 direction(right、left、down、up)重复一个物品。gap 是步长,而不是间距:1 表示相邻,2 表示副本之间隔一个空槽,0 的行为等同于 1。repeatY 会在垂直方向的轴上重复整行。没有 direction 时,count、gap 和 repeatY 都会被忽略,只放置一个槽位。这些字段计算的是槽位数量,而不是物品的堆叠数量。

重叠。 当两个槽位占用同一个格子时,有实际作用的那个(带点击动作、标签或存储槽位的)会胜过纯装饰性的,与声明顺序无关。在同类的两个槽位之间,后声明的胜出。系统会记录一次指明该格子的警告。

点击动作​

interactionList 将点击类型映射到命令和触发器。可用的类型有 LEFT_CLICK、RIGHT_CLICK、SHIFT_LEFT_CLICK、SHIFT_RIGHT_CLICK、MIDDLE_CLICK、DOUBLE_CLICK、NUMBER_KEY_1 到 NUMBER_KEY_9、DROP、DROP_ALL 和 SWAP_OFFHAND。

  • commands 由控制台执行。%player% 会被替换为玩家名称,PlaceholderAPI 占位符会先被解析。
  • triggers 会为该玩家触发 TypeWriter 条目。槽位自身的 triggers 和 modifiers 会在每次左键或右键点击时触发,或在某个特定交互匹配时触发。
  • closeMenu 会在动作执行后关闭窗口。executeReturn 会返回上一个菜单。

以 gui: 开头的命令由 GUI 自身处理:

命令效果
gui:close关闭菜单。
gui:back重新打开该会话的上一个菜单。
gui:open <entry_id> 或 gui:action <entry_id>触发另一个条目,通常是另一个 Open GUI。
gui:view <view_id>切换到另一个视图,而不关闭物品栏。
gui:page <delta> [layout_id]让分页或排行榜布局翻动相应的页数。
gui:scroll <dx> <dy> [layout_id]滚动一个 scrollable 布局。
gui:refresh立即重绘菜单。
gui:sound <sound_key>向玩家播放一个声音。

打开、返回与关闭​

从另一个菜单打开的 Open GUI 会被推入会话历史,因此 gui:back 或 executeReturn 可以返回到它。按 Escape 关闭会结束会话。打开 book 布局会先结束当前会话。

设置 audio 可在打开、关闭、滚动和点击时播放声音。设置 autoRefreshTicks 可在菜单打开期间每 N 个 tick 重绘一次,这正是让名称和 lore 中的占位符像计数器或计时器一样跳动的原因。

视图、标签页与继承​

views 让一个 open_gui 变成共用同一外壳的多个界面。layoutId 为 @view 的 frame 会由当前视图的布局来填充:首先是该视图显式的 frames 映射,然后是名为 <view id>_<frame id> 的布局,最后是对视图 parentId 进行同样的查找。将标签物品的 buttonPrefix 设为 view:,并把 buttonType 设为视图 id,点击时它就会切换视图,并在激活期间高亮。视图标题支持 {breadcrumb}、{view} 和 {root}。

baseMenuId 指向另一个 Open GUI,并把它的 layoutPool、views 和 storagePool 合并到你的菜单之下:id 相同的布局会替换被继承的布局。详情请参见视图、标签页与继承。

存储槽位​

GUI Storage artifact 按玩家或按组保存物品。在条目的 storagePool 中声明可复用的配置,然后为物品设置 storageId,或使用 storage 布局。存储槽位的物品名称和 lore 支持 {stored_name}、{stored_amount} 和 {stored_max}。使用 source 的排行榜行还可以使用 {score_raw} 和 {value_<key>}。

默认的点击绑定,你可以在 GUI Global Settings 中修改:

操作默认点击方式
从光标放入一个物品左键点击
放入光标上的整组物品Shift + 左键点击
取出一个物品右键点击
取出全部左键点击
取出一组Shift + 右键点击
从物品栏填充交换副手(F)
将所有物品丢在地上丢弃(Q)

dropOnClose 会在菜单真正关闭时(按 Escape 或断开连接时,但不包括玩家切换到另一个菜单时),把仍存放在其中的物品丢在玩家脚下。

扩展物品栏​

extendToPlayerInventory 会把玩家自己的 36 个槽位显示为额外的四行,形成十行的画布(y 为 0 到 9)。它仅在客户端生效:真实的物品栏永远不会被修改,并会在菜单关闭时恢复,而且无法从底部几行拿起物品。它要求 guiType 为 CUSTOM 且 size 为 SIZE_54。id 以 _extended 结尾的根布局会自行启用它。

配置​

GUI 没有配置文件。可以用两个可选的 manifest 条目进行调整:

  • GUI Extension Configuration 用于启用 debug 日志,以及默认开启的 hideVanillaItemStats 选项,该选项会隐藏菜单按钮上的攻击伤害、耐久度和附魔行。
  • GUI Global Settings 用于设置存储的点击绑定以及技能树连接线物品。

占位符​

占位符返回值
%typewriter_gui_storage_amount_<entry_id>_<slot_index>%玩家在某个 GUI Storage 条目中存放的物品数量,为空时返回 0。
%typewriter_gui_storage_has_<entry_id>_<slot_index>%槽位中有物品时为 true,否则为 false。

<slot_index> 是存储槽位的 y * 9 + x。这些占位符始终读取玩家自己的存储,绝不会读取共享的组存储。

在菜单内部,扩展会替换以下标记:{stored_name}、{stored_amount}、{stored_max}(存储槽位),{page}、{next_page}、{prev_page}、{total_pages} 和 {page_indicator}(分页布局的 INDICATOR 按钮),以及 {rank}、{name}、{score}、{group}、{world} 和 {score_<fact_id>}(排行榜行)。

条目​

6 个条目,由扩展源码生成。

动作1
构件2
清单3

故障排查​

菜单打开后是空的。 mainLayoutId 为空,或与 layoutPool 中任何布局的 id 都不匹配(id 区分大小写)。使用 baseMenuId 时,留空的 mainLayoutId 会回退为父级的值。启动检查会在控制台中报告无法解析的主布局。

缺少某个槽位,控制台提示 “falls outside the grid”。 该物品落在了负数的 x 或 y,或超出了第 8 列。这通常来自过大的 count,因为它计算的是槽位数。日志会指出布局和被拒绝的坐标。

控制台提示 “Slot overlap ... gap”。 两个槽位占用了同一个格子。gap 是步长:1 表示槽位相邻,2 表示每个之间隔一个空槽,因此把 gap: 1 理解为“一个间隔”的作者,会让副本叠在相邻副本的位置上。请修改 gap 或移动其中一个槽位。

某个槽位管理员能看到,玩家却看不到。 viewPermission 指定了一个只有 OP 才拥有的权限。空值会被忽略,但拼写错误会变成一个真实存在、仅限 OP 的权限节点。视图的 viewPermission 也适用同样的规则。

按钮能显示但没有任何作用。 请依次检查 clickPermission、cooldownTicks,然后是 criteria。如果该槽位有 buttonType,其 buttonPrefix 必须与提供它的扩展匹配;无人认领的标签只会保留你自己的 interactionList,除此之外没有任何作用。命令由控制台运行,因此需要玩家作为发送者的命令会静默失败。

可滚动的内容不会移动。 请检查内容是否比窗口大(virtualWidth 和 virtualHeight):只有在该方向上还有可滚动的内容时,箭头才会显示。如果 showDefaultButtons 关闭且没有 buttons,则完全没有箭头。当默认箭头所在的格子已经有内容物品、按钮或装饰时,它也会让出位置:控制台不会有任何记录,因此请在 GUI Settings 的 scrollArrows 中移动它,或在被滚动区域之外添加带有 direction 和 step 的自定义 buttons。

排行榜只列出在线玩家。 请在排行榜的 population 字段中链接一个 GUI Leaderboard Population artifact,以保留离线玩家最后已知的数值。

扩展菜单没有显示十行。 extendToPlayerInventory 需要 guiType 为 CUSTOM 且 size 为 SIZE_54。

相关扩展​

  • Shops — 基于 GUI 布局和 shop_button: 标记构建的商店菜单。
  • Quest Codex — 任务日志菜单,基于同一个 open_gui 底板构建。