UiCustomization
模组对原版游戏界面(Shell UI)的扩展点集合。与 ModContext.panels() 的「独立悬浮弹窗」不同,本能力提供的是嵌入原版固定 UI 区域的扩展点:主界面底部状态栏自定义块、结算覆盖渲染、轨道样式覆盖、光标接管。经 ctx.uiCustomization() 获取(进程级,游戏启动后任意时刻可用)。
方法速览
| 方法 | 用途 |
|---|---|
addStatusBarItem(String, String) | 在主界面底部状态栏加一个自定义块 |
settings() | 取设置场景扩展入口 |
addResultOverlay(String, ResultOverlayRenderer) | 结算界面附加自绘 |
addTrackStyleProvider(String, TrackStyleProvider) | 覆盖轨道视觉样式 |
addCursorRenderer(String, CursorRenderer) | 整体接管自绘光标 |
完整签名
public interface UiCustomization {
StatusItemHandle addStatusBarItem(String id, String text);
default SettingsExtension settings();
default void addResultOverlay(String id, ResultOverlayRenderer renderer);
default TrackStyleHandle addTrackStyleProvider(String id, TrackStyleProvider provider);
default void addCursorRenderer(String id, CursorRenderer renderer);
interface StatusItemHandle {
void setText(String text);
void setOnClick(Runnable onClick);
void remove();
}
interface ResultOverlayRenderer {
void render(RenderCanvas canvas, ResultSnapshot snapshot, ResultLayout layout);
}
interface TrackStyleProvider {
TrackStyle styleFor(TrackStyleQuery query);
}
interface TrackStyleQuery {
String trackId();
boolean isFake();
int index();
}
interface TrackStyleHandle {
void remove();
}
interface CursorRenderer {
void render(RenderCanvas canvas, CursorState state);
}
}addStatusBarItem(String id, String text)
签名:
StatusItemHandle addStatusBarItem(String id, String text);行为:在底部状态栏注册一个自定义块。块以凸起 bevel 按钮样式渲染在 ITEM 块右侧,按注册顺序从左到右排列;状态栏剩余空间不足时,靠后的块跳过绘制(不显示、不响应点击),窗口变宽后自动恢复。
id为模组内唯一标识,完整键为模组id:本id;id为null或空串抛IllegalArgumentException。text为null时按空串处理;建议 12 字符以内(状态栏为单行等宽字体)。- 同一模组重复注册相同
id属幂等:更新文本并复用既有块(返回绑定该块的新句柄)。 - 句柄详见 StatusItemHandle。
示例:
UiCustomization.StatusItemHandle item =
ctx.uiCustomization().addStatusBarItem("mymod", "示例模组");
item.setOnClick(() -> ctx.getLogger().info("clicked"));
item.setText("示例模组·已启用");settings()
签名:
default SettingsExtension settings();行为:返回绑定当前模组的设置场景扩展入口(见 SettingsExtension)。宿主未实现该扩展点时(旧宿主)抛 UnsupportedOperationException("宿主未实现设置场景扩展点"),调用方应视为可选扩展点。当前宿主实现直接返回按模组绑定的注册视图。
示例:
SettingsExtension ext;
try {
ext = ctx.uiCustomization().settings();
} catch (UnsupportedOperationException e) {
return; // 旧宿主:没有该扩展点
}addResultOverlay(String id, ResultOverlayRenderer renderer)
签名:
default void addResultOverlay(String id, ResultOverlayRenderer renderer);行为:结算界面全部原版内容(窗口、判定行、按钮)绘制完成后,宿主按注册顺序依次调用各渲染器,模组可在画布任意位置附加自绘内容。
id为null/ 空串或renderer为null抛IllegalArgumentException。- 同 id 重复注册属幂等(替换渲染器),注册顺序按首次注册的位置。
- 渲染在游戏渲染线程执行,异常由宿主隔离(不影响结算界面与其它模组);单次耗时超过 5ms 会有限频优化提示。
- 旧宿主未实现时抛
UnsupportedOperationException("宿主未实现结算覆盖扩展点")。
示例:
ctx.uiCustomization().addResultOverlay("watermark", (canvas, snapshot, layout) -> {
canvas.drawText("MY MOD", layout.windowX() + 8, layout.windowY() + 16,
TextStyle.of(14, java.awt.Color.GRAY));
});addTrackStyleProvider(String id, TrackStyleProvider provider)
签名:
default TrackStyleHandle addTrackStyleProvider(String id, TrackStyleProvider provider);行为:游玩场景渲染时每帧、每条轨道(真 / 假)向各模组查询样式覆盖。
id为null/ 空串或provider为null抛IllegalArgumentException。- 多模组按注册顺序查询,首个返回非
null的提供器整体生效(不做字段级合并),返回null表示该轨道保持引擎默认。 - 同 id 重复注册属幂等(替换提供器,保留首次注册的位置)。
- 新注册项若不处于注册顺序首位,宿主输出
[ModConflict]限频告警(它已被"首个生效"语义遮蔽)。 - 覆盖纯视觉,不影响判定与输入;真轨道快捷键框 / 背景 / 分隔线在 Z 分层路径与默认路径下均应用覆盖。
- 旧宿主未实现时抛
UnsupportedOperationException("宿主未实现轨道样式扩展点")。 - 返回的
TrackStyleHandle.remove()按完整键移除,下一渲染帧恢复引擎默认;模组停用时宿主自动清理。
示例:
UiCustomization.TrackStyleHandle handle = ctx.uiCustomization().addTrackStyleProvider(
"tint", query -> query.isFake() ? null : new UiCustomization.TrackStyle(
0x3300FFAA, true, null, null, null, null, null));
// 不再需要时
handle.remove();addCursorRenderer(String id, CursorRenderer renderer)
签名:
default void addCursorRenderer(String id, CursorRenderer renderer);行为:宿主需要绘制自绘光标时,若存在注册的接管渲染器,按注册顺序取首个整体替代引擎默认光标绘制(不做字段级合并)——该帧引擎默认的四角框 / 十字准星不再绘制,完全由模组负责。
id为null/ 空串或renderer为null抛IllegalArgumentException。- 同 id 重复注册属幂等(替换渲染器,保留首次注册的位置)。
- 回调在游戏渲染线程、每渲染帧至多一次;
RenderCanvas逻辑坐标即 1280×720 虚拟光标坐标系(与 CursorState 的x/y同源)。 - 异常由宿主隔离:视为未接管,回退引擎默认自绘(光标不会消失)。
- 非首位的注册项不会生效,宿主输出
[ModConflict]限频告警。 - 旧宿主未实现时抛
UnsupportedOperationException("宿主未实现光标接管扩展点")。
示例:
ctx.uiCustomization().addCursorRenderer("dot", (canvas, state) -> {
canvas.setColor(java.awt.Color.WHITE);
canvas.fillRect(state.x - 3, state.y - 3, 6, 6);
});线程:注册 / 更新 / 移除任意线程可调用(宿主注册表以 synchronized 保护)。点击回调在游戏线程触发(可直接调用场景跳转等要求游戏线程的 API);结算渲染与光标接管在游戏渲染线程执行,回调内不应做阻塞操作。TrackStyleProvider.styleFor 每帧每轨调用一次,应返回缓存的样式对象(按状态变化时才重建),避免每帧分配;异常由宿主隔离(视为返回 null)。
生命周期:模组停用或游戏退出时,宿主自动移除该模组注册的全部定制项与设置项;模组无需(也不应在 onUnload 中逐个 remove,重复 remove 无害但多余)。
稳定性:2.0 起冻结:2.x 内只增不破。