基于 VexView 的高度自定义 UI 配置化插件。通过配置文件定义 GUI 界面、组件布局和交互事件,无需写Jvav即可创建复杂的UI
- Bukkit/Spigot 1.8 ~ 1.12
- VexView >=2.6.10
- PlaceholderAPI (可选)
前往 Actions 页面,点击最近一次构建,在底部 Artifacts 区域下载 AerVexUI 压缩包,解压后即可得到 JAR 文件。
- 将
VexView.jar放入服务端plugins/目录 - 将
AerVexUI-1.0.0.jar放入服务端plugins/目录 - 启动服务端,生成
plugins/AerVexUI/目录 - 在
plugins/AerVexUI/ui/下创建你的 UI 配置文件
| 命令 | 说明 | 权限 |
|---|---|---|
/aervexui open <ui> [player] |
打开指定UI. 当player参数为空时为执行者打开. 控制台必须指定player | aervexui.admin |
/aervexui reload |
重载配置文件 | aervexui.admin |
/aervexui list |
列出所有已加载的UI | aervexui.admin |
配置文件在 plugins/AerVexUI/ui/ 下,以文件名作为UI名
no-pointer: false # true->不呼出鼠标, false=普通交互GUI. true了可以当成hud用
render-time: 114514 # nopointer下 UI的显示时长, 单位tick. 不写默认永久
origin: left-top # 坐标系原点
window:
title: '<背景贴图URL>'
x: 0
y: 0
width: 200
height: 150
closable: true
groups:
<分组id>:
<组件id>:
x: '...'
y: '...'
width: '...'
height: '...'
type: '...'
# ... 其他属性
event:
onClick:
- '...'
events:
<事件id>:
onClick:
- '...'| 字段 | 类型 | 说明 |
|---|---|---|
title |
String | GUI 背景贴图url |
x |
String | GUI 显示 X 坐标 |
y |
String | GUI 显示 Y 坐标 |
width |
String | GUI 宽度 |
height |
String | GUI 高度 |
closable |
boolean | 是否允许玩家通过 Esc/E 键关闭. 默认 true |
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
no-pointer |
boolean | false |
不呼出鼠标指针. true 时玩家可正常操作游戏, UI上的button类型组件可以通过打开聊天栏时用鼠标点击 |
render-time |
int | 2147483647 |
组件显示时长(tick, 1秒=20tick). 仅 no-pointer: true 时生效 |
origin |
String | left-top |
坐标原点,决定 x/y 的参考位置 |
HUD 模式(no-pointer)下 input 类型组件不支持, 会被跳过. 按钮点击依赖 VexView 的 ButtonClickEvent
| 原点值 | 说明 |
|---|---|
left-top |
左上角(默认). x 向右, y 向下 |
left-bottom |
左下角. x 向右, y 向上 |
left-center |
左侧居中. x 向右, y 从中心上下偏移 |
right-top |
右上角. x 从右向左, y 向下 |
right-bottom |
右下角. x 从右向左, y 向上 |
right-center |
右侧居中. x 从右向左, y 从中心上下偏移 |
center-top |
正上方居中. x 从中心左右偏移, y 向下 |
center-bottom |
正下方居中. x 从中心左右偏移, y 向上 |
center-center |
正中心 |
原点同时影响 window 位置和组件坐标
x y width height 支持以下单位
| 单位 | 示例 | 说明 |
|---|---|---|
px |
100或100px |
像素(默认) |
% |
50% |
相对于父容器(GUI = window, HUD = 屏幕) |
vw |
50vw |
相对于屏幕宽度 |
vh |
50vh |
相对于屏幕高度 |
用法实际上就跟html是一样的
不带单位时默认为px. 单位可以和表达式混合使用 比如 '(50 + 10)%
所有组件都支持以下字段:
| 字段 | 类型 | 说明 |
|---|---|---|
x |
String | X 坐标 |
y |
String | Y 坐标 |
width |
String | 宽度 |
height |
String | 高度 |
type |
String | 组件类型 image、button、text、input |
event |
Object | 事件定义 (内联或引用) |
logo:
x: '10'
y: '10'
width: '50'
height: '50'
assets: '[local]logo.png'
type: 'image'| 字段 | 说明 |
|---|---|
assets |
组件素材 |
confirm_btn:
x: '60'
y: '100'
width: '80'
height: '20'
assets: '[local]btn_normal.png'
assets2: '[local]btn_hover.png'
type: 'button'
text: '确认'
name: 'confirm'
event:
onClick:
- '-msg 你点击了按钮'| 字段 | 说明 |
|---|---|
assets |
按钮默认状态贴图url |
assets2 |
按钮悬停状态贴图url |
text |
按钮显示文本 |
name |
按钮内部名称 |
title_text:
x: '10'
y: '10'
width: '180'
height: '20'
type: 'text'
text:
- '§6§l标题'
- '&7副标题内容'
scale: 1.2| 字段 | 说明 |
|---|---|
text |
文本内容列表,每项为一行 |
scale |
文本缩放比例,默认 1.0 |
search_box:
x: '20'
y: '50'
width: '160'
height: '20'
type: 'input'
maxString: 50
id: 0
text: '默认文本'| 字段 | 说明 |
|---|---|
maxString |
最大输入字数,默认 50 |
id |
输入框 ID,同一 GUI 内不可重复 |
text |
预置文本内容 |
x、y、width、height 字段支持数学表达式,可以引用其他组件的属性.
- VexView坐标系:X轴向右增大,Y轴向下增大,原点为 GUI 左上角
- 表达式求值仅支持整数运算
分组id.组件id.属性
支持的属性:x、y、width(或 w)、height(或 h)
groups:
main:
header:
x: '10'
y: '10'
width: '180'
height: '20'
type: 'text'
text: ['标题']
content:
x: '10'
y: '(main.header.y + main.header.height + 10)'
width: '180'
height: '100'
type: 'text'
text: ['内容区域']
footer:
x: '(main.content.x + main.content.width - 80)'
y: '(main.content.y + main.content.height + 5)'
width: '80'
height: '20'
type: 'button'
assets: '[local]btn.png'
text: '确定'支持的运算符:+、-、*、/,支持括号 () 控制优先级
表达式在 UI 打开时一次性求值,结果为整数
以下占位符可在 text、assets、命令等所有文本字段中使用:
| 占位符 | 说明 |
|---|---|
%player_name% |
玩家名称 |
%player_displayname% |
玩家显示名 |
%player_health% |
玩家当前血量(int) |
%player_level% |
玩家经验等级 |
%player_x% |
玩家 X 坐标(int) |
%player_y% |
玩家 Y 坐标(int) |
%player_z% |
玩家 Z 坐标(int) |
%player_world% |
玩家所在世界名 |
如果 PlaceholderAPI 存在,支持使用占位符
| 事件 | 触发时机 | 支持组件 |
|---|---|---|
onClick |
鼠标点击组件 | button |
onType |
任意非移动键按下 | 所有(通过 GUI 内组件监听) |
onType_<key> |
指定按键按下 | 所有 |
onClose |
GUI 关闭时 | 所有 |
onOver |
鼠标悬停(仅 HoverText 显示) | 所有(通过 VexHoverText) |
escape、1-0、backspace、tab、enter、lshift、rshift、lalt、space、f1-f12、up、down、left、right
注意:VexView 不监听 WASD 移动键,因此 onType_w、onType_a、onType_s、onType_d 无法使用
方式一:内联定义
my_button:
# ...
event:
onClick:
- '-msg 你好'方式二:引用 events 节
my_button:
# ...
event: 'events.my_event'
events:
my_event:
onClick:
- '-msg 你好'方式三:引用其他组件的事件
my_button:
# ...
event: 'main.other_button.onClick'格式:分组id.组件id.事件类型
事件中可使用的命令按顺序由上到下执行
- '-set -g 分组id -r 组件id --url "<新URL>" --x "10" --y "20"'-r 参数不允许为空. 支持的 -- 参数:--url、--url2、--name、--x、--y、--width、--height
- '-create -g 分组id -r 组件id --type "button" --assets "[local]btn.png" --x "10" --y "20" --width "80" --height "20" --text "按钮" --event "events.my_event"'如果要创建的组件已存在,等同于先执行 -delete -g 分组id -r 组件id forever 再创建
通过 -create 创建的组件不在原始配置中,因此无法直接定义 event. 可通过以下方式指定:
--event eventId:引用events节中定义的事件--event 分组id.组件id.eventType:复用其他组件的事件
组件ID(reactId)在同一 GUI 内应唯一. 如果 -create 创建了与已有组件相同分组和 ID 的组件,会先删除旧组件再创建新组件
由于 OpenedVexGui.addDynamicComponent() 限制动态添加的组件如果assets非[local]来源,图片不会显示. 因此 -create 和 -vis true 操作的组件assets应使用 [local]
- '-delete -g 分组id -r 组件id temp'
- '-delete -g 分组id -r 组件id forever'temp:临时删除,下次打开 UI 时会根据配置文件重新表现forever:永久删除,直到插件重载才会重新表现
我用最直白最不绕弯子最..的话向你解释:forever 删除的组件在 /aervexui reload 后会恢复,temp 删除的组件在重新打开 GUI 时恢复
- '-refresh -g 分组id -r 组件id'一般用于 assets URL 内容变更后刷新显示. 执行时会移除再重新添加组件
- '-vis -g 分组id -r 组件id true'
- '-vis -g 分组id -r 组件id false'
- '-vis -g 分组id -r 组件id show'
- '-vis -g 分组id -r 组件id hidden'true = show = 显示,false = hidden = 隐藏
由于 OpenedVexGui.addDynamicComponent() 限制动态添加的组件如果assets非[local]来源,图片不会显示. 因此 -create 和 -vis true 操作的组件assets应使用 [local]
- '-console say 服务器公告'
- '-console give %player_name% diamond 1'以控制台身份执行命令
- '-cmd default spawn'
- '-cmd op gamemode creative %player_name%'default:以玩家当前权限执行op:临时提升为op权限执行,执行后恢复原权限
- '-msg &a操作成功!'
- '-msg 你好,%player_name%'向触发事件的玩家发送消息
- '--if player.hasPermission("aervexui.use")'
- '-msg 你有权限'--if 后面的内容为Jvav表达式,通过Nashorn执行. 可用变量:
| 变量 | 类型 | 说明 |
|---|---|---|
player |
Player |
触发事件的玩家对象 |
Bukkit |
Bukkit |
Bukkit 静态工具类 |
plugin |
AerVexUI |
插件实例 |
示例:
- '--if player.getLevel() >= 10'
- '--if player.isOp()'
- '--if player.getHealth() > 5'
- '--if player.hasPermission("vip.rank3")'- '--if player.isOp()'
- '-msg 你是管理员'
- '--else'
- '-msg 你不是管理员'相当于
if (player.isOp()) {
player.sendMessage("你是管理员");
} else {
player.sendMessage("你不是管理员");
}- '--if player.isOp()'
- '-msg 管理员消息'
- '--exitif'
- '-msg 这条消息不受 if 影响'相当于
if (player.isOp()) {
player.sendMessage("管理员消息");
}
player.sendMessage("这套消息不受 if 影响");--exitif 终止最近的 --if 块. 如果不加 --exitif,后续所有命令都在该 --if 内部执行
条件支持嵌套,通过栈管理:
- '--if player.isOp()'
- '--if player.getLevel() >= 50'
- '-msg 高级管理员'
- '--else'
- '-msg 普通管理员'
- '--exitif'
- '--exitif'
- '-msg 不受任何条件影响'相当于
if (player.isOp()) {
if (player.getLevel() >= 50) {
player.sendMessage("高级管理员");
} else {
player.sendMessage("普通管理员");
}
}
player.sendMessage("不受任何条件影响")window:
title: '[local]menu_bg.png'
x: -1
y: -1
width: 250
height: 200
closable: true
groups:
header:
title:
x: '25'
y: '10'
width: '200'
height: '20'
type: 'text'
text:
- '§6§l服务器菜单'
scale: 1.5
player_info:
x: '25'
y: '(header.title.y + 30)'
width: '200'
height: '30'
type: 'text'
text:
- '§7玩家: §f%player_name%'
- '§7等级: §f%player_level% §7血量: §c%player_health%'
buttons:
warp_btn:
x: '25'
y: '(header.player_info.y + 40)'
width: '90'
height: '25'
assets: '[local]btn_normal.png'
assets2: '[local]btn_hover.png'
type: 'button'
text: '传送大厅'
event:
onClick:
- '-cmd default spawn'
- '-msg &a已传送到大厅'
shop_btn:
x: '(buttons.warp_btn.x + buttons.warp_btn.width + 15)'
y: '(buttons.warp_btn.y)'
width: '90'
height: '25'
assets: '[local]btn_normal.png'
assets2: '[local]btn_hover.png'
type: 'button'
text: '商店'
event:
onClick:
- '-cmd default shop'
admin_btn:
x: '25'
y: '(buttons.warp_btn.y + buttons.warp_btn.height + 10)'
width: '200'
height: '25'
assets: '[local]btn_admin.png'
assets2: '[local]btn_admin_hover.png'
type: 'button'
text: '管理面板'
event:
onClick:
- '--if player.isOp()'
- '-create -g admin -r panel --type "text" --x "25" --y "140" --width "200" --height "30" --text "§c管理面板已打开"'
- '--else'
- '-msg §c需要管理员权限'
- '--exitif'
footer:
close_btn:
x: '(250 - 90 - 15)'
y: '(200 - 25 - 10)'
width: '90'
height: '25'
assets: '[local]btn_close.png'
assets2: '[local]btn_close_hover.png'
type: 'button'
text: '关闭'
event:
onClick:
- '-vis -g buttons -r admin_btn hidden'
events:
admin_panel_event:
onClick:
- '-console say %player_name% 打开了管理面板'License: GPL-3.0 | QQ/VX: AerMini | Mail: aermini@163.com