Tab 在线列表
福利模块
Tab 属于福利模块,消费额度满 ¥300 或 找我购买高级会员 即可获得授权码。启用后仍需在 license.yml 中配置对应授权码。
功能定位
通过 ArcartX TAB UI 渲染自定义在线列表,支持排序、分组、内置变量、跨服。
核心特性
- 多视图 / 命令切换:每个 tab 可绑定
view标签,玩家通过/axstab view <name>在多套布局间切换 - 分组:按内置变量表达式分桶,可在每组之前插入
header-pack - 分页:客户端
Packet.send("TAB_PAGE", "next/prev/set", N)翻页,或/axstab page <id> <next|prev|N> - 跨服聚合:
aggregate.enabled: true时每个服务器在 Tab 中只占一行(常用于网络总览视图) - 退服宽限:
settings.leave-grace-ms让玩家退服后短时间内仍出现在跨服快照中,避免跨服跳传时的"闪烁" - 多键复合排序:
sort-keys列表按优先级递减组合多个排序键,单键支持name/prem/papi三种模式 - 三种单键排序兼容写法:
name— 按玩家名字母排序prem— 按权限组排序,优先级列表自定义(如 admin > vip3 > vip2 > default)papi— 按内置变量排序(如%player_health%),支持数字/文本排序
- 过滤器:
filters.include/filters.exclude按内置变量表达式或权限节点过滤;hide-vanished: true一键隐藏隐身玩家 - 置顶 / 置底:
pinned.top/pinned.bottom把管理员、好友等强制锁在头部/尾部 - 灵活 pack 格式:字符串、列表、字典三种模式,按每个玩家渲染内置变量后发给 UI
- 周期同步:服务端按配置间隔(默认 20 tick)自动 diff 推送,客户端无需主动刷新
- 客户端刷新入口:保留客户端
Packet.send("TAB", "update")兼容入口,带限流保护 - 跨服玩家列表:Redis Pub/Sub 或代理通道同步远程服务端玩家列表,超时自动移除过期快照
- 条目过滤:支持
max-entries限制条目数、omit-blank-values跳过空值 - 称号前后缀集成:Tab 模块不再解析外部 PAPI 占位符。如需在 pack 中展示称号,请通过 Title 模块或其他模块提供的能力接口实现。
内置变量
Tab 模块内置占位符解析器,无需安装 PlaceholderAPI 即可使用以下变量。这些变量可在 pack、sort-keys、filters、grouping、aggregate.line-pack 中直接使用。
Player 变量
| 占位符 | 说明 |
|---|---|
%player_name% | 玩家名 |
%player_displayname% / %player_display_name% | 玩家显示名 |
%player_uuid% | 玩家 UUID |
%player_world% | 所在世界名 |
%player_x% / %player_y% / %player_z% | 整数坐标 |
%player_health% | 当前血量 |
%player_max_health% | 最大血量 |
%player_ping% | 延迟(ms) |
%player_gamemode% | 游戏模式 |
%player_scoreboardteam% | 计分板队伍名(无队伍返回空串) |
Server 变量
| 占位符 | 说明 |
|---|---|
%server_online% | 在线人数 |
%server_max_players% | 最大人数 |
%server_name% | 服务器名称 |
%server_version% | 服务端版本 |
%server_motd% | MOTD |
%server_tps% / %server_tps_1% | 最近 1 分钟 TPS |
%server_tps_5% | 最近 5 分钟 TPS |
%server_tps_15% | 最近 15 分钟 TPS |
无法识别的占位符会原样保留在文本中。Tab 模块不再调用外部 PlaceholderAPI,因此 Vault、EssentialsX 等第三方扩展的占位符(如
%vault_primary_group%)将不会被解析。
依赖
| 类型 | 依赖 | 作用 | 缺少时表现 |
|---|---|---|---|
| 必需 | ArcartX | 自定义 TAB UI、玩家条目包和客户端刷新 | 模块无法替换 TAB 界面 |
| 可选 | 宿主 cross-server + Redis | 多服 Tab 快照同步(大快照建议 Redis) | 单服 TAB 正常,跨服玩家列表关闭 |
启用步骤
Tab 是福利模块,启用前需要先完成 license.yml 授权激活。
modules:
tab:
enabled: true关键配置(ArcartXTab.yml)
settings:
debug: false
register-ui-on-enable: true
overwrite-ui-file: false
refresh-interval-ticks: 20
cross-server:
enabled: false
# Tab 定义目录,相对模块数据目录。
# 目录下每个 *.yml 文件为一个 Tab 定义,文件名(去掉 .yml)即为定义 ID。
tabs-directory: "tabs"Tab 定义文件位于 data/tab/tabs/*.yml,文件名即定义 ID。
跨服连接在宿主 config.yml → cross-server;模块 ArcartXTab.yml 的 cross-server.enabled 为总开关。详见 跨服通信架构。
# data/tab/tabs/online-tab.yml
enabled: true
ui-id: "tab"
packet-handler: "tab"UI / Packet
| 功能 | UI ID | 说明 |
|---|---|---|
| 在线列表 | tab | 服务端按 refresh-interval-ticks 周期 diff 推送;客户端 Packet.send("TAB", "update") 触发一次强制重发(受 client-refresh-guard 限流) |
UI 注册 ID 由
ArcartXTab.yml中tabs.<id>.ui-id决定,默认tab。模块内置 UI 文件为arcartx/ui/tab.yml,启动时复制到plugins/ArcartXSuite/ui/tab.yml。
排序、过滤与置顶
以下示例均为
data/tab/tabs/<定义ID>.yml文件内的根级字段,不再写tabs:前缀。
多键复合排序 sort-keys
按优先级递减组合多个排序键,命中第一个键相同的项再按下一个键比较。填写 sort-keys 后,旧字段 sort-mode / sort-papi-key / sort-papi-numeric / sort-prem-group / sort-descending 全部失效。
# data/tab/tabs/online-tab.yml
sort-keys:
- { mode: prem, prem-group: [admin, vip3, vip2, vip1, default] }
- { mode: papi, key: "%player_health%", numeric: true, order: desc }
- { mode: name }| 字段 | 适用模式 | 说明 |
|---|---|---|
mode | 全部 | name / prem / papi |
key | papi | 内置变量表达式,如 %player_health% |
numeric | papi | 是否按数字解析后排序 |
prem-group | prem | 优先级列表,未列出的玩家归 default |
order | 全部 | asc(默认)/ desc;也可写 descending: true |
跨服模式(
cross-server: true)下,远程节点只接收首个 sortKey 作为代表排序值,本地多键排序仅在本服内完整生效。
过滤器 filters
# data/tab/tabs/online-tab.yml
filters:
hide-vanished: false # 一键隐藏隐身玩家
include: # 任一命中保留;为空表示不过滤
- { papi: "%player_world%", equals: "world" }
exclude: # 任一命中剔除
- { permission: "axs.tab.hide" }
- { papi: "%player_gamemode%", equals: "SPECTATOR" }- 规则字段:
papi+equals(内置变量模式)或permission(权限模式),二选一。 equals留空时,规则只判断"内置变量渲染结果非空且不等于原表达式",可用于探测变量是否存在。invert: true反转单条规则判定("不持有 / 不匹配")。- 隐身集成:
hide-vanished: true检测 Bukkitplayer.metadata("vanished"),命中即隐藏(绝大部分隐身插件都会写入此 metadata)。
置顶 / 置底 pinned
# data/tab/tabs/online-tab.yml
pinned:
top:
- { permission: "axs.tab.pin-top" } # 管理员置顶
bottom:
- { permission: "axs.tab.pin-bottom" }命中 top 的玩家排在所有"中间层"之前;命中 bottom 的排在最后。三个分桶各自再用 sort-keys 内部排序,因此置顶后仍保持权限组/内置变量排序结果。
视图、分组、分页
多视图 view
每个 tab 定义可以挂在一个 view 标签下(默认 "default")。玩家通过 /axstab view <name> 切换当前视图,此时:
- 与玩家新 view 相同的 definitions 立刻重发;
- 其他 view 的 definitions 各发一个空 payload 用于清空 UI。
# data/tab/tabs/list-default.yml
view: "default"
# ...
# data/tab/tabs/list-team.yml
view: "team"
# ...玩家命令:
/axstab view:查看当前 view/axstab view <name>:切换 view/axstab refresh:强制重发当前 view 的所有 tab
分组 grouping
按内置变量把已排序玩家分桶并在每组之前可选输出 header-pack。仅 string / list 形态的 pack 支持分组。
# data/tab/tabs/online-tab.yml
grouping:
enabled: true
group-by-papi: "%player_scoreboardteam%"
group-order: ["admin", "vip3", "vip2", "vip1", "default"]
include-unordered: true
header-pack: "&6=== {group} ==="{group} 在 header-pack(无论 string / list / map / key 名)中被替换为当前组键。header 内的内置变量按该组第一个玩家上下文渲染。
分页 pagination
# data/tab/tabs/online-tab.yml
pagination:
enabled: true
page-size: 80
packet-id: "TAB_PAGE"
next-action: "next"
prev-action: "prev"
set-action: "set"客户端翻页:
# 在 UI YAML 中给翻页按钮:
events:
onClick:
actions:
- "[packet] TAB_PAGE,next"
# 或绝对页:
- "[packet] TAB_PAGE,set,2"服务端命令:/axstab page <definitionId> <next|prev|N>。页码越界会自动收敛到最后一页。
跨服聚合 aggregate
仅当 cross-server: true 时生效。启用后 Tab 不展开玩家,每个服务器只占一行。常用于跨大区 BungeeCord / Velocity 网络中的服务器总览视图。
# data/tab/tabs/network-overview.yml
cross-server: true
aggregate:
enabled: true
line-pack: "&b{server-display} &7- &f{server-online} 人在线"line-pack 支持以下花括号占位符:
| 占位符 | 含义 |
|---|---|
{server-id} | 服务器节点 ID |
{server-display} | 同 server-id(保留作为后续自定义渲染入口) |
{server-online} | 当前节点在线人数 |
内置变量仍按本服第一个在线玩家上下文渲染。
跨服增强:批节流与退服宽限
settings.batch.window-ticks 控制跨服快照广播的最小间隔(ticks,50ms/tick)。0 = 禁用节流;推荐 = refresh-interval-ticks,可避免玩家进退服触发的短时间快照风暴。
settings.leave-grace-ms 控制玩家退服后在跨服快照中保留虚拟条目的毫秒数。典型场景:玩家跨服跳传时旧服立刻把他从 Tab 移除、新服稍后才出现,造成短暂"消失";启用宽限后旧服在该时间窗内仍保留该条目,等新服快照接管。
玩家头像(PlayerSkin 渲染)
Tab pack 中已内置 {player_uuid} 渲染变量,服务端不抓 Mojang、不缓存皮肤,玩家头像由 ArcartX 客户端 UI 端的 PlayerSkin:<UUID> 纹理表达式直接渲染,跨服同样适用。
服务端 pack 把 UUID 输出给 UI:
# data/tab/tabs/online-tab.yml
pack:
name: "%player_name%"
uuid: "{player_uuid}"
health: "%player_health%"内置完整示例:模块自带两套示例 UI(启用时自动复制到
plugins/ArcartXSuite/ui/),都在ArcartXTab.yml中以enabled: false形式提供,把对应 definition 切到true即可体验(建议同时关掉tabs.online-tab.enabled避免双 HUD):
tab-rich+tabs.demo:头像 + PVP 视觉风格的完整版"在线列表"形态。tab-arena+tabs.arena:CS / LOL 风格的双队 PVP 计分板——红蓝左右分栏 / 常驻显示 / 按住 TAB 切换详细模式 / 队友战斗状态图标。队伍来源默认%player_scoreboardteam%。UI 端按packet.get(i).team在客户端拆桶(不依赖服务端 grouping,因 map pack 在服务端 grouping 下会退化)。
UI YAML 端(arcartx/ui/tab.yml)在 packetHandler 中把 packet.uuid 赋给行控件的变量,Texture 控件再用 PlayerSkin: 渲染:
controls:
player_row:
type: Canvas
children:
head:
type: texture
attribute:
width: 24
height: 24
normal: "PlayerSkin:{var.uuid}"
name_text:
type: text
attribute:
texts: "{var.name}"
{player_uuid}是 Tab 模块的内置花括号占位符,由服务端直接替换为玩家 UUID,不依赖任何外部插件。
内置示例:tab-arena(竞技场 / 枪战 PVP 计分板)
启用方式:将 data/tab/tabs/arena.yml(首次启动自动导出)中的 enabled 改为 true(建议同时把 data/tab/tabs/online-tab.yml 中的 enabled 改 false)。
定义文件(data/tab/tabs/arena.yml):
enabled: true
ui-id: "tab-arena"
packet-handler: "tab"
client-refresh-packet-id: "TAB"
client-refresh-action: "update"
sort-keys:
- { mode: papi, key: "%player_scoreboardteam%" }
- { mode: name }
pack:
team: "%player_scoreboardteam%"
uuid: "{player_uuid}"
name: "%player_name%"
health: "%player_health%/%player_max_health%"UI 端要点(arcartx/ui/tab-arena.yml):
- 常驻显示:
defaultOpen: true,计分板始终在屏幕顶部;按住 TAB 切换"详细模式"(显示血量)。 - 双队分栏:左红右蓝,
packetHandler按packet.get(i).team值决定copy到哪侧 VGrid:
packetHandler:
tab: |-
// ...(清理旧条目)
while(i <= packet.size()){
if(val.red_player_row.width == 320){
if(packet.get(i).team == "red"){
ROW = val.red_player_row.copy('red_' + var.ArenaTAB刷新轮次 + '_' + i)
} else if(packet.get(i).team == "blue"){
ROW = val.blue_player_row.copy('blue_' + var.ArenaTAB刷新轮次 + '_' + i)
}
ROW['head'].normal = 'PlayerSkin:' + packet.get(i).uuid
ROW['name_text'].texts = packet.get(i).name
ROW['health_text'].texts = "&c❤ " + packet.get(i).health
ROW.visible = true
i++
}
}- 每行控件:
head(PlayerSkin:头像)+name_text(玩家名)+health_text(仅详细模式 visible)。 - 队伍来源替换:修改
pack.team的内置变量表达式 + UI 端== "red"/== "blue"判定值即可适配不同队伍系统。
命令
权限:
arcartxsuite.admin
| 命令 | 说明 |
|---|---|
/axs tab status | 查看 Tab 模块状态 |
/axs tab reload | 重载 Tab 配置并刷新在线玩家显示 |
玩家命令(无需 arcartxsuite.admin):
| 命令 | 说明 |
|---|---|
/axstab view [name] | 查看 / 切换当前 view |
/axstab page <id> <next|prev|N> | 翻页 |
/axstab refresh | 强制重发当前 view |
/axstab debug <player> [id] | 排序 / 分组 / 状态调试快照(权限:axstab.debug 或 OP,控制台亦可) |
/axstab snapshot save <name> | 把当前在线玩家 + 跨服快照落盘到 data/tab/snapshots/<name>.json |
/axstab snapshot load <name> | 把存档注入为 snapshot:<name>:<nodeId> 虚拟节点,本服 viewer 立即可见(dev 用) |
/axstab snapshot unload <name|all> | 卸载该 name 对应的全部虚拟节点 |
/axstab snapshot list | 列出已保存的快照 + 已注入的虚拟节点 |
/axstab snapshot delete <name> | 删除存档文件(不影响已注入的虚拟节点) |
视觉风格 settings.style
Tab 模块内置 PVP 检测窗口,通过 TabPvpListener 监听玩家攻击/受击事件:
- pvp-highlight:玩家造成或受到伤害后,
window-ms内isPvpActive()返回true。此状态用于/axstab debug调试输出,不再对外暴露 PAPI 占位符。
settings.style 当前仅保留 pvp-highlight 相关字段:
settings:
style:
pvp-highlight:
enabled: false
window-ms: 5000调试
/axstab debug <player> [definitionId] 打印玩家当前 definition 的:
- 多键排序
sort-keys的 numeric / string 值 - 分组键
group-key - 是否命中
pinned-top/pinned-bottom view/page/rank- 是否隐身、是否 PVP、ping
local-visible-count/total-visible-count
未指定 definitionId 时输出全部 definition。控制台与玩家均可调用(需 axstab.debug 权限或 OP)。
dry-run 模式
settings:
debug-tools:
dry-run: false开启后服务端完整跑一遍渲染流程(filters / sortKeys / pinned / grouping / pagination / 内置变量解析),但不调用 bridge.sendPacket(...),客户端 Tab 保持上一次状态。配合 settings.debug: true 会逐 viewer 输出 ArcartXTab[dry-run] skip send def=... viewer=... 日志,用于:
- 生产排查:玩家投诉显示异常时,开 dry-run + debug 观察服务端实际算出的 payload,不影响其他在线玩家。
- 配置预演:改完排序键/grouping 后先 dry-run 看日志,确认正确再关闭重发。
- 性能基线:单独测量"渲染计算耗时"vs"网络发包耗时"。
snapshot 调试快照
存档目录:plugins/ArcartXSuite/data/tab/snapshots/<name>.json,格式 version: 2,包含:
localEntries:本服每个 definition 的TabRemoteEntry列表(含sortValues/sortStringValues/groupKey/renderedPack)。remoteSnapshots:当前已知的真实跨服节点快照(不包含snapshot:*虚拟节点,避免循环嵌套)。
load <name> 把存档注入为 snapshot:<name>:local + snapshot:<name>:<原 nodeId> 形式的虚拟跨服节点,与真实跨服节点一同进入 buildCrossServerPayload 渲染。snapshot:* 节点在 cleanupStaleSnapshots 中豁免清理,必须由 unload <name> / unload all 显式移除。
限制:load 路径不重新解析内置变量,使用存档落盘时的
renderedPack。这意味着存档中玩家的%player_health%等占位符值是落盘时刻的快照,不会跟随真实玩家变化。该行为用于"忠实复现"调试场景,不适合作为长期跨服数据源。
安全提示:load 会让本服所有 viewer 看到存档玩家。请仅在测试服或受控环境使用,并在排查完成后及时
unload。