Xerr API

Xerr renders Minecraft HUD layouts through resource-pack fonts and core shaders. This reference is for plugin developers who need to render a named layout, supply variables, or manage a player's ActionBar/BossBar content.

Xerr 通过资源包字体和核心着色器绘制 Minecraft HUD。本页面向需要渲染布局、传入变量或管理玩家 ActionBar/BossBar 的插件开发者。

Entry point / 唯一入口

External plugins should start from XerrAPI; runtime *Service objects are implementation details and are not part of the stable v2 contract.

外部插件统一从 XerrAPI 开始调用;运行时 *Service 仅供 Xerr 内部使用,不属于稳定的 v2 接口。

XerrAPI.popups.show(player, "notice")
XerrAPI.screens.play(player, "yellow_transition")
XerrAPI.get().popups().show(player, "notice");
XerrAPI.get().screens().play(player, "yellow_transition");

Start with a layout / 从布局开始

A layout ID is the top-level key in a file under plugins/Xerr/core/layout/, not the filename. For example, a hud_info: section is referenced by "hud_info".

布局 ID 是 plugins/Xerr/core/layout/ 文件中的顶层键,不是文件名。例如 hud_info: 对应 "hud_info"。

import com.hiusers.xerr.api.XerrAPI

val component = XerrAPI.layouts.render(
player,
"hud_info",
mapOf("name" to player.name)
)

null means the layout ID is not registered or has no renderable elements. For frequent rendering, use renderAsync() instead of waiting for Kether and placeholders on the calling thread.

返回 null 表示布局未注册或没有可渲染元素。频繁渲染时使用 renderAsync(),不要在当前线程等待 Kether 与占位符计算。

Coordinates / 坐标

GuiAnchor(x, y) uses GUI width/height percentages measured from the top-left: (0, 0) is the top-left corner and (100, 100) is the bottom-right. Element x is a pixel offset to the right; element y is a pixel offset upward when positive. Without anchor, the rendering target's own origin is used.

GuiAnchor(x, y) 是从左上角开始计算的 GUI 宽高百分比:(0, 0) 为左上角,(100, 100) 为右下角。元素的 x 正数向右,y 正数向上,并统一表示元素顶部;原生 TTF 基线由字体指标自动换算。不写 anchor 时使用显示目标本身的原点。

Inventory GUI titles ignore anchors. Use a separate anchor-free layout for titles and regenerate the resource pack after adding a new custom-font text offset.

背包 GUI 标题不应用锚点;标题建议使用不带 anchor 的独立布局。增加自定义字体的文字偏移后,请重新生成资源包。

Distribution / 资源包交付

The API returns components; the client still needs the resource pack produced by /xerr pack. This documentation build does not modify the plugin JAR, a running server, or its configuration.

API 返回文本组件;客户端仍须加载 /xerr pack 生成的资源包。生成本文档不会改动插件 JAR、运行中的服务端或其配置。

Player heads / 玩家头像

Head styles live in plugins/Xerr/core/template/head/*.yml. The template ID is a top-level YAML key, not a filename. Each file can define multiple templates; subdirectories only organize files. For example, a portrait: section in any file is referenced as portrait. An ordinary layout element references the style through head.template; its outer coordinates keep the usual positive-Y-upward convention. The defaults are mask: square (square portrait) and render: flat (face and hat composited together); layered offsets the hat one pixel left/up.

头像模板位于 plugins/Xerr/core/template/head/*.yml,顶层 YAML 节点就是模板 ID,不是文件名;同一文件可定义多个模板,子目录只用于分类。例如任意文件中的 portrait: 节点都通过 portrait 引用。普通布局元素用 head.template 引用;外层坐标仍为 Y 正数向上。自带 portrait.yml 直接说明四种目标类型及对应字段,修改配置时无需翻阅文档;README 也有完整示例。默认 mask: square 为方形;render: flat 表示脸和帽子叠在一起,layered 则把帽子向左上错开 1 像素。

party_face:
face:
anchor:
x: 100
y: 0
x: -40
y: -40
head:
template: portrait
target:
type: variable
key: target_uuid
XerrAPI.layouts.renderAsync(
player,
"party_face",
mapOf("target_uuid" to partyLeaderUuid.toString()),
"party_sidebar"
)

viewer uses the viewer, player uses a fixed uuid or name, and variable reads the named layout variable. kether uses a script returning a Player, UUID, player name or null, with a positive refresh interval in ticks. It never waits on the render thread. Give separate instances of the same layout different stable renderContext IDs; built-in ActionBar, BossBar and inventory rendering already do this.

viewer 显示观看者自己;player 固定指定 uuid 或 name;variable 读取布局变量。kether 的脚本可返回 Player、UUID、玩家名或 null,refresh 为正数 tick 间隔,渲染线程不会等待脚本。复用同一布局的多个实例应传入不同、稳定的 renderContext,防止动态目标互相覆盖;内置 ActionBar、BossBar、背包标题已自动隔离。

Skin downloads/decode are bounded and cached. The resource pack contains shared white-pixel glyphs, not player-specific textures; changing a target or invalidating a skin does not require rebuilding the pack. Adding a template/position/size still requires /xerr pack. Inventory titles remain synchronous: uncached targets/skins use the configured fallback and can appear on a later open, without canceling or resending the open-window packet.

皮肤下载、解码使用有界后台线程池和缓存。资源包只有共用的白色像素字形,不包含每个玩家的皮肤;换目标、换皮肤无需重新打包。新增模板、坐标或尺寸仍需 /xerr pack。背包标题保持同步:未缓存的目标/皮肤显示占位图,后续打开可使用完成的缓存,不取消或补发开窗包。

Custom skin providers / 接入换肤插件

import com.hiusers.xerr.api.head.HeadSkins

// Return a future of the full decoded 64×32 or 64×64 skin, not just its face.
// 返回完整 64×32 / 64×64 皮肤的 BufferedImage Future,不是仅 8×8 的脸。
val registration = HeadSkins.registerSkinProvider { uuid ->
skinService.loadSkinAsync(uuid)
}

// Call after a skin changes. / 玩家换肤后调用。
HeadSkins.invalidate(changedPlayerUuid)

// Close on your plugin's disable. / 自己的插件关闭时解除注册。
registration.close()

Providers run on a skin worker and must use thread-safe APIs rather than access Bukkit directly. Returning null or failing defers to the next provider, then the online/Mojang profile. Each provider is waited on for at most three seconds on a worker only. Registration and closing invalidate cached skins; UUID invalidation also clears resolved name aliases and rejects late results.

提供器在皮肤工作线程调用,应使用线程安全接口,不直接操作 Bukkit。返回 null 或失败会交给下一个来源,最后使用在线/Mojang 档案;单个提供器只在工作线程最多等待三秒。注册、关闭句柄都会使皮肤缓存失效;按 UUID 刷新也会清除对应的玩家名缓存并丢弃旧请求的迟到结果。

Popups / 弹窗

Popup displays and their popup types live together in core/display/popups/**/*.yml. A display defines its channel, anchor, finite slots and FIFO queue; each nested popup ID references an ordinary Xerr Layout. Holding duration excludes entrance/exit, and queued or preparing instances do not consume it.

弹窗显示组是 YAML 顶层节点,组内 popups 的键是命令、Kether 和 API 使用的 Popup ID。显示位满时排队;排队和内容准备不消耗停留时间;退场结束释放显示位,补位结束再接纳下一条。

import com.hiusers.xerr.api.XerrAPI

XerrAPI.popups.show(player, "notice", mapOf("message" to "获得钻石 ×3"))
.thenAccept { popup ->
popup.updateVariables(mapOf("message" to "获得钻石 ×5"))
popup.renew()
popup.close() // exit animation / 播放退场
// popup.close(true) // immediate / 立即清除
}

show() returns a future completed on admission, not after display. Each handle has a UUID, owner, popup/group IDs, state, variable snapshot, shown future and finished future. The UUID overload is suitable for asynchronous callers; all mutations dispatch to the server thread. A failed initial frame ends only that instance; a failed refresh retains its last good frame. Offline/reload clears entries and rejects late results.

show() 接纳后即完成,句柄可能仍在排队;句柄包含 UUID、所属玩家、Popup/分组、状态、变量快照、首次显示与结束 Future。异步调用者可传玩家 UUID,修改会回主线程。第一次渲染失败释放显示位;后续刷新失败保留上一帧。离线、重载立即清理,结束时释放临时头像脚本上下文。

XerrAPI.popups.list(playerId, groupId) lists live handles; find(playerId, instanceId) resolves an owned live UUID; clear(playerId, groupId, popupId, force) supports scoped cleanup. finished reports expired/stopped/cleared/offline/reload/failed. No offline persistence is performed.

list 查询未结束实例,find 只查该玩家自己的 UUID,clear 按组/Popup ID 清理。等待 Future 不阻塞主线程;内容脚本不要等待自身实例,否则会产生自等待。Kether syntax, animation settings and the sampled opacity resource precision are documented in README; adding shader/font variants still requires client rendering tests.

Progress images / 图片进度

LayoutEntityProgress.fill automatically slices a full PNG in six directions. Optional transition animates values and trail adds a delayed damage layer. Numeric sampling is independent of tick animation; instance state is isolated and cleared on removal, quit or reload. Existing lists and repeated segments remain available. Ordinary component/string API calls and inventory titles return immediate snapshots; built-in HUD containers and popups compose live frames.

LayoutEntityProgress.fill 将一张完整 PNG 自动裁切成六种方向的进度;可选 transition 为数值缓动,trail 为延迟扣血拖尾。数值采样与逐 tick 动画分开,实例相互隔离,移除、离线和重载清理旧状态。原有图片列表、重复分段仍可用。普通组件/字符串 API 与背包标题返回即时快照,内置 HUD 容器和弹窗负责动态帧合成。配置及完整说明见 docs/progress.md,默认配置在 core/layout/hud_info.yml 和 core/layout/hotbar.yml,图片分包见 docs/asset-packages.md。

Compass / 罗盘

compass.template embeds a live horizontal compass in existing persistent Actionbar/Bossbar layouts. Compass templates define appearance; XerrAPI.compasses manages session targets, entity following, scripted locations and namespaced provider snapshots. Target updates never regenerate textures. Captions refresh independently from yaw; reload invalidates old asynchronous work while retaining valid target IDs. See docs/compass.md and the annotated core/template/compasses/navigation.yml / core/layout/compass_example.yml examples.

registerProvider is for externally owned live snapshots. registerStorage returns a plugin-scoped CompassStorageRegistration: Xerr owns target lifecycle and versioned serialization, while the adapter only implements asynchronous read, write and delete. Multiple plugins are isolated by plugin-name namespaces.

Lifecycle events / 生命周期事件

All lifecycle events extend TabooLib BukkitProxyEvent, are non-cancellable result notifications, and are delivered on the Bukkit primary thread. Register listeners with @SubscribeEvent.

所有生命周期事件都继承 TabooLib BukkitProxyEvent,是不可取消的结果通知,统一在 Bukkit 主线程触发,并使用 @SubscribeEvent 注册监听:

  • PopupStartEvent: prepared content starts entering/displaying; queued and failed-before-first-frame instances do not emit it.

  • PopupEndEvent: emitted once with EXPIRED, STOPPED, CLEARED, OFFLINE, RELOAD or FAILED.

  • ScreenStartEvent, ScreenMarkerEvent, ScreenEndEvent: scene markers expose the configured marker name and tick.

  • CompassTargetAddEvent, CompassTargetRemoveEvent: managed API/command/Kether/storage targets only. Same-ID updates and provider snapshots do not emit add/remove events. cause distinguishes API, storage load and storage unload.

import taboolib.common.platform.event.SubscribeEvent

@SubscribeEvent
fun onCovered(event: ScreenMarkerEvent) {
if (event.marker == "covered") {
// teleport, change world, start dialogue, etc.
}
}

Stack and HUD channels / Stack 与 HUD 通道

Persistent HUD definitions live in core/display/huds/**/*.yml; channel: bossbar and channel: actionbar select only the transport. The one global Stack uses core/display/stack/settings.yml plus recursively loaded Row files under stack/rows. Every Stack Item references a local Layout, while External BossBars are configured independently in core/display/external-bossbars.yml.

常驻 HUD、全局 Stack 和 External BossBars 共用按玩家维护的主 BossBar。Stack API 使用 StackSettings、StackRow、StackItem 与 StackService;外部条使用 ExternalBossbarService。详见 docs/stack.md。

Packages

Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard