Skip to Content
Guide简介

DearOreUI — Minecraft 基岩版 OreUI 的运行时扩展

DearOreUI 是一个跑在 LeviLamina 26.10.x 客户端里的原生 C++20 模组。它直接 Hook Minecraft 基岩版的 OreUI 渲染引擎,在真实客户端里注入你自己的 UI。


0. OreUI 的问题

Minecraft 基岩版的 UI 层是个黑盒。OreUI(Coherent Gameface)驱动着世界列表、设置、商城这些界面,但它的页面结构、生命周期和注入点都没有公开文档。

想自定义 UI 的 Mod 开发者其实只有两条路:

  • 改资源包。脆弱、随版本失效,多个 Mod 改同一资源还会互相覆盖。
  • 放弃。

市面上已有的 OreUI 工具(比如 Ore-UI-Customizer)是离线改包工具,改完要重启游戏,不能在游戏内实时注入,也谈不上多 Mod 协作。

DearOreUI 把这三件事补上:运行时注入、多 Mod 共存、出了问题能查。


1. 能力一览

能力说明状态
真实显示链路Hook OreUI::View::initialize 捕获真实 cohtml::View*,等 OnReadyForBindingsExecuteScript 注入,用 CSSOM 构建 DOM 覆盖层真实客户端验证通过
声明式 UIregisterOverlay / registerPanel / registerButton / registerPage / registerComponent,几十行代码挂一个界面已交付
组件库37 种 ComponentKind(14 个原子组件 + 23 个 8.1.4 组合/布局组件)+ 主题令牌已交付
多 Mod 协作统一注册表、依赖排序、冲突检测、变换计划已交付
双向桥接C++→JS(ExecuteScript / triggerEvent);JS→C++(Host 方法 + Facet + 权限校验)JS→C++ 已打通,同页多次调用受限
全链路诊断diagnostics.jsonl 结构化事件流 + 21 项能力矩阵 + vtable 指纹已交付
零侵入不修改游戏安装目录、不改原版 #root、失败自动回退设计原则,已执行

2. 渲染链路是什么样

下面这条链路在真实客户端里验证过,不是纸面设计:

ScreenTechStackSelector::getTechStackForScreen ← 判断当前页面是否为 OreUI 技术栈 SceneProvider::createScene ← 页面创建(PageCreated 生命周期) Router 路由方法 ← 页面导航(路径/查询/片段) OreUI::View::initialize ← 捕获真实 cohtml::View*(MCAPI 导出符号) OreUI::View::$OnReadyForBindings ← 脚本上下文就绪门控(关键) CoherentHostBridge::sendScript ← 有界延迟队列 + 冲刷 cohtml::View::ExecuteScript(script) ← 引擎真实执行 JS 页面内 bootstrap → CSSOM 构建 DOM ← 在全屏 Overlay 中渲染

2.1 验证记录(2026-08-15 真实客户端)

验证项结果
cohtml::View vtable 指纹与 mcmeta 头文件布局逐槽位一致(GetId/GetTaskFamilyId/GetWidth/GetHeight/EnableImmediateLayout/IsImmediateLayoutEnabled 等 getter 全部吻合)
ExecuteScript 槽位索引 60 正确
TriggerEvent 槽位索引 75 正确
显示结果demo overlay(全屏红遮罩 + 居中 “DearOreUI DEMO” 绿字)在世界列表页正常显示
门禁未命中 view 时 isAvailable()=false,页面加载零副作用

document.createElement 在真实 OreUI 页面里执行,结果直接渲染到屏幕上。预览器里能跑通的不算数,这里说的是游戏里真的显示出来了。

2.2 踩过的几个坑

难点解决方式
ExecuteScript 提交太早会被引擎静默丢弃OnReadyForBindings(脚本上下文创建后)再提交,门控 + 有界延迟队列
cohtml 会丢弃 innerHTML 注入的 style 属性只用 element.style.cssText,CSSOM 是唯一可靠通道
position: fixed 百分比会塌缩容器全屏 + 子层 absolute; top/left/right/bottom: 0 撑满
不同版本 ABI 会漂移用 vtable 机器码指纹做校验,不写死偏移

3. 扩展模型

3.1 一个最小的 UI

#include "ll/api/mod/RegisterHelper.h" #include "api/IDearOreUIApi.h" #include "api/manifest/ModManifest.h" #include "api/manifest/UiManifest.h" using namespace dearoreui::api; // IDearOreUIApi* oreui = ...; // 稳定获取方式见 environment 页,当前参考内置 Demo bool onLoad() { // 1. 注册 Mod(前置条件:资源/UI 注册都要求 Mod 已注册) ModManifest manifest; manifest.id = ModId{"my-first-ui"}; manifest.modNamespace = "my_first_ui"; manifest.modVersion = Version{1, 0, 0}; auto modResult = oreui->registerMod(manifest); if (modResult.isErr()) return false; // 2. 声明 Overlay:在哪个页面、锚在哪、要不要吃指针事件 UiManifest ui; ui.modNamespace = "my_first_ui"; ui.id = "hello"; ui.kind = UiKind::Overlay; ui.pageScopes = {PageScope::Any}; // 所有 OreUI 页面 ui.anchor = UiAnchor::Center; ui.fingerprint = "hello-overlay-v1"; // 冲突检测用 return oreui->registerOverlay( ModId{"my-first-ui"}, ui, "<div>Hello, DearOreUI!</div>" ).isOk(); } LL_REGISTER_MOD(MyMod, onLoad);

调用链是 registerMod → Manifest 校验 → 注册表 → registerOverlay → 冲突检查 → UiPlanner 生成计划 → MountManager 挂载 → RuntimeInjector 注入 → 页面渲染。每个环节都会写诊断事件。

3.2 声明式组件

组件库的用法是不手写 htmlBody 字符串,改用组件规格树描述 UI:

component::ComponentSpec panel; panel.kind = component::ComponentKind::Panel; panel.label = "DearOreUI"; component::ComponentSpec text; text.kind = component::ComponentKind::Text; text.variant = "heading"; text.label = "DEMO"; component::ComponentSpec button; button.kind = component::ComponentKind::Button; button.variant = "primary"; button.label = "OK"; panel.children.push_back(text); panel.children.push_back(button); oreui->registerComponent(ModId{"dearoreui"}, uiManifest, panel);

ComponentSpec 树经过 ComponentRenderer 变成 DomNode 树,再走通用的 CSSOM 渲染器,和普通 Overlay 是同一条管线。组件怎么拼、字段代表什么,见组件总览

3.3 多 Mod 协作

Mod A 注册(manifest + 资源 + 脚本 + 样式 + UI) Mod B 注册 Mod C 注册 统一注册表(IModRegistry) 按页面/版本/能力筛选 依赖排序(DependencyResolver) 冲突检测(ConflictDetector,指纹/路径/命名空间) 变换计划(ChangePlanner / PageTransformer) 注入当前 OreUI 页面
  • 失败隔离:一个 Mod 失败不影响其他 Mod;一个页面失败不影响其他页面。
  • 可回退:每个注册返回句柄,可注销;Runtime 关闭时全量清理。
  • 版本化变换VersionConstraintDependencyconflicts 显式声明,未验证版本默认不可用。

4. API 按难度分六层

API 按难度逐级开放,普通 Mod 停在 L1 就够,复杂扩展再往上走:

L0 运行时查询 —— 只读、零副作用(isReady / capabilities / protocolVersion) L1 声明式资源注册 —— 资源 / 脚本 / 样式 / UI 声明式注册 L2 页面生命周期订阅 —— PageContext / 页面事件 L3 受控 Host API —— 权限校验的 C++↔JS 双向调用 L4 版本化代码变换 —— 依赖排序 / 冲突检测 / 变换计划 L5 Facet Provider —— 宿主能力抽象 L6 高级兼容适配 —— vtable 指纹 / 多版本 ABI 适配

公开门面(dearoreui::api):

门面职责关键方法
IRuntimeApi运行时查询getInfo / getCapabilities / checkSupport / getProtocolVersion / isReady
IModApiMod 生命周期registerMod / unregisterMod / setModEnabled
IResourceApi资源注册registerResource / registerScript / registerStyleSheet
IHostApi宿主桥接registerHostMethod(带 Permission 白名单)
IUiApiUI 挂载registerOverlay / registerPanel / registerButton / registerPage / registerComponent

5. 诊断

所有注册、计划、注入、失败都会写进 diagnostics.jsonl。每个事件带 idtimestampseveritycategorycontextIdmodIdpageIderrorCodefields

  • 能力矩阵CapabilitySet 公开 21 项能力的支持等级(Unknown/Unsupported/Experimental/Supported)。运行时支持到什么程度,查一下就知道。
  • vtable 指纹转储:多版本 ABI 探测留下的机器码级证据。
  • Stage 0~7 遥测:每个阶段都留有独立的遥测事件,从运行时事实探测到显示链路打通。

Host 方法强制校验权限,一共 9 项:

权限
资源读resource.read
资源注册resource.register
页面观察page.observe
UI 挂载ui.mount
Host 只读host.read_only
Host 写host.write
资源变换transform.resource
Bundle 变换transform.bundle
诊断读diagnostic.read

6. 给 AI / 自动化开发者的约定

  • 契约先行api/ 门面是纯虚接口,命名空间 dearoreui::api;文档站示例与源码契约逐一对应,不凭文档想象。
  • 能力矩阵机器可读Capability + SupportLevel,AI 可以按能力查询决定生成什么代码,不生成运行时不可用的 API。
  • 渐进式 L0–L6:生成代码的复杂度与能力等级匹配;普通场景生成 L1 声明式代码即可。
  • 显式错误Result<T> / ErrorCode 贯穿所有公共 API,集成代码可以显式处理冲突、校验失败、无效参数。
  • 版本与兼容VersionConstraint、能力矩阵、VerifiedSince 字段,兼容性判断有据可依。

7. 工程保障

维度保障
单元测试阶段 4~7 全部单元测试通过(注册/计划/挂载/注入/变换)
回归门禁每次改动不得破坏既有测试;demo 特判替换为通用渲染器时要求回归通过
失败隔离ExecuteScript 由 executor 包裹,异常不向上传播影响页面生命周期
门禁约束未命中 view 回退 NullHostBridge;不修改原版 #root;不替换原版资源
构建Windows x64 客户端变体,CI 自动构建 + 发布产物 DearOreUI-windows-x64.zip

8. 路线图

阶段 0~7.1 已交付 Hook 候选验证 / 公共类型与诊断 / Runtime-Mod-API 门面 / Hook-Capability-PageContext / Source-Resource-Inject / IPC-Host-Facet / 多 Mod 注册表-冲突-变换 / UI 挂载与声明式 UI / 真实显示链路打通 阶段 8 已交付(2026-08-22 核对) 通用渲染器(htmlBody→CSSOM)/ 组件库(37 种 ComponentKind + 主题令牌)/ JS→C++ Facet 通道(单发限制)/ API 门面(Runtime/Resource/Mod/UI/Host 五组接口)

阶段 8 的验收标准是:

  • ≥5 个原版风格组件可被示例 Mod 在 OreUI 页面显示并交互。
  • 外部 Mod 通过公开 API 完成「注册组件 → 页面显示 → JS 调用 C++ Host → 事件回传」全链路。
  • v1.0 候选:单元测试 + 回归 + 真实客户端验证通过;诊断事件完整;卸载无悬挂。

这两条已经做到;v1.0 候选收敛还在路上,见路线图


9. 边界

边界说明
页面范围只覆盖 OreUI 技术栈页面(如 /play/all);主菜单 / 世界内为 JsonUI,单独立项调研
JS→C++ 通道已打通(游戏原生 Facet 协议),但每个 OreUI View 目前只有一次有效 dispatch,同页多次请求待攻坚
外部 API 入口当前参考内置 Demo 的 runtime::IRuntime::api(),稳定获取方式见在你的模组中使用

10. FAQ

Q: 这会修改我的游戏安装目录吗? A: 不会。DearOreUI 完全运行时注入,不写游戏安装目录、不改原版资源。模组数据(诊断等)输出到 LeviLamina 数据目录。

Q: 多个 Mod 都用 DearOreUI,会打架吗? A: 不会。统一注册表 + 依赖排序 + 冲突检测 + 变换计划,冲突显式报错而非静默覆盖。

Q: 我只想弹个窗,需要懂 OreUI 内部吗? A: 不需要。L1 声明式注册就够;OreUI/Coherent/vtable 的复杂性由运行时承担。

Q: 支持哪个 Minecraft 版本? A: 目标 LeviLamina 26.10.x / Bedrock 26.10.x / Windows x64,能力矩阵与版本探测保证兼容性有据可依。

Q: 我在主菜单/世界内看不到 UI? A: 那些是 JsonUI 技术栈,不在当前覆盖范围;阶段 8 聚焦 OreUI 页面,JsonUI 注入单独立项。


下一步