UGC2.0经验补全:基建、跨端、创作运行时与源码复盘
自动关联目录:UGC2.0经验补全:基建、跨端、创作运行时与源码复盘
这篇是 UGC2.0 的完整技术底座,不是最终背诵稿。它一方面还原本人直接做过的页面协议、原生宿主、制品、多端构建和自动化;另一方面把对象模型、三 VM、编辑/试玩运行时、网络、云资产和玩法能力补成系统架构。两部分必须使用不同主语。
一、经验边界与时间边界
1.1 经验来源
| 层级 | 定义 | 可以怎么说 | 典型范围 |
|---|---|---|---|
X1 直接交付 | 有个人提交、设计、联调或交付证据 | 我负责、我设计并实现 | PixUI 页面协议与宿主、制品构建、多端出包、UI 自动化 |
X2 项目内参与 | 接过上下游、做过适配或排障 | 我参与、我负责其中的…… | 元件管理 UI 联调、材质二进制化、试玩发布恢复、AI 编辑器集成 |
X3 源码复盘 | 团队平台能力,本人结合当前源码补全 | 团队系统、我复盘后的理解 | Instance 对象模型、三 VM、完整编辑运行时、网络复制、云资产、技能与行为系统 |
1.2 时间口径
- 2026.08 - 2026.10 是本人以 UGC2.0 基建为工作重心的阶段。
- Web/PixUI 经验在 2026.06 起已经积累,与 UGC2.0 有技术连续性,但不能把所有 Web 业务页面都算作 UGC2.0。
- 当前源码仍在快速演进。页面框架、多端构建和自动化与本人时间窗口直接重合;多关卡、完整三 VM 和部分运行时能力需要逐项区分当期版本与后续演进。
1.3 一句话口径
我在 UGC2.0 直接负责的核心不是一个页面,而是页面运行基础设施、内容制品和跨端交付三块:把 TypeScript 页面、Lua 编辑服务和 C++ PixUI 宿主之间的协议与生命周期补完整;把 JSON/二进制转换和 ArtifactBuilder 接进保存发布;再打通 Android、iOS、自动化和 UI 可测试性。对象模型、三 VM、运行时网络和完整玩法能力属于团队平台,我已经基于源码补全,但不会说成个人独立设计。
二、UGC2.0 的产品与技术本质
UGC1.0 以受控元件和属性配置为主要表达单元;UGC2.0 更进一步,需要提供接近“可编程世界运行时”的统一基础。它至少同时是:
- 对象系统:用统一 Instance 树表达场景、服务、角色、脚本和 UI。
- 创作 IDE:对象树、属性、Gizmo、脚本、预制体、撤销和调试共同工作。
- 多角色运行时:编辑、客户端试玩和服务端试玩拥有独立 VM 与生命周期。
- 内容编译链:作者源经过冻结、校验、转换、制品化和发布,成为可验证的运行输入。
- 跨端宿主:PC、Android、iOS 和其他目标在不同能力边界下使用同一内容语义。
- 平台生态:对象、脚本、资产和运行时 API 必须支持权限、版本、安全和长期兼容。
完整闭环:
创建工程
-> Instance 树与资产初始化
-> 场景 / 属性 / 脚本 / UI 编辑
-> 撤销、保存、预制体和本地验证
-> 冻结作者快照
-> ArtifactBuilder 计划、转换、校验和提交
-> 上传 / 发布 / 下载 / 缓存
-> Client / Server VM 加载制品并试玩
-> 自动化、日志和性能证据回流三、总体架构
| 层 | 核心职责 | 关键边界 |
|---|---|---|
| 创作界面层 | React/TypeScript 页面、对象树、属性、工具栏、资源与脚本面板 | 页面只持有展示状态,领域状态由运行时服务拥有 |
| 页面运行层 | 页面注册、栈、生命周期、原生 PixUI 视图、消息协议 | 逻辑页面与原生 View 分离;旧页面消息必须失效 |
| 编辑领域层 | 选择、Gizmo、命令、事务、撤销、预制体和编辑服务 | 所有修改走可审计命令或事务,不让 UI 直接改底层对象 |
| 对象与脚本层 | DataModel/Instance、属性、信号、Service、Luau、绑定 | 稳定身份、反射契约、VM 隔离和安全 API |
| Play 运行层 | Client/Server VM、场景、角色、技能、行为、网络和多关卡 | 编辑态与试玩态不共享活对象;服务端保持权威 |
| 内容与资产层 | JSON、FlatBuffers、QZBIN、Prefab、Bundle、云资产 | 作者源与发布制品分离;格式版本与语义版本分离 |
| 构建与交付层 | ArtifactBuilder、多端构建、发布下载、缓存和预加载 | 不可变输入、确定性输出、失败无半成品、全链可验证 |
| 质量与运维层 | UI 自动化、白盒、日志、性能、兼容和诊断 | 测试使用稳定语义标识;每层留下可关联证据 |
五条主链:
- 编辑链:输入 -> 页面命令 -> Lua 编辑服务 -> 编辑事务 -> Instance 树 -> 页面状态更新。
- 页面链:逻辑路由 -> 原生 View -> 页面上下文 -> 订阅领域 -> suspend/resume/dispose。
- 运行链:作者快照 -> 制品 -> Client/Server VM -> 场景与服务 -> 网络游玩。
- 交付链:Inventory -> Processor DAG -> 事务输出 -> Manifest -> Verify -> 发布。
- 质量链:协议测试 -> 浏览器组件测试 -> UE 自动化 -> 真机构建与运行证据。
四、完整模块图谱
4.1 对象模型与编辑内核
| 模块 | 层级 | 业务价值 | 实现与追问点 |
|---|---|---|---|
| DataModel/Instance 树 | X3 | 用统一层级表达世界和服务 | 稳定 ObjectId、父子关系、类信息、销毁语义、遍历 |
| Class 与继承 | X3 | 给创作者稳定的能力分类 | 类注册、继承检查、默认对象、版本、API 暴露 |
| Property 与 Attribute | X2/X3 | 统一属性编辑、脚本访问和序列化 | 元数据、类型转换、只读、默认值、变更信号 |
| Signal/Event | X3 | 让对象和服务低耦合协作 | 连接句柄、解绑、错误隔离、跨 VM/网络边界 |
| ServiceProvider | X3 | 通过服务而非全局变量访问平台能力 | 服务注册、角色准入、生命周期、测试替身 |
| 对象身份与引用 | X3 | 支持保存、复制、撤销和跨文件引用 | ID 生成、引用解析、悬空引用、重映射 |
| SceneSubsystem | X3 | 向不同 VM 提供当前 World 的场景门面 | 绑定注入、角色差异、World 清理、事件桥接 |
| 选择与 Outliner | X2/X3 | 连接视口对象与编辑器树 | 选中唯一权威、多选、深层节点、对象销毁 |
| Gizmo 与变换 | X2/X3 | 提供移动、旋转和缩放 | 拖拽事务、坐标空间、吸附、输入穿透 |
| 属性面板 | X1/X2 | 基于元数据编辑不同类型对象 | Schema 驱动、批量值、混合态、校验、提交节流 |
| Undo/事务 | X3 | 保证创作操作可逆和可组合 | 事务边界、对象快照、嵌套、回滚、脏标记 |
| Prefab 与自定义类 | X2/X3 | 复用对象结构与能力 | 模板身份、实例覆盖、依赖、升级、断链 |
| 编辑态脚本 | X3 | 让工具和对象在编辑时执行逻辑 | 准入 API、事件、资源预算、与试玩隔离 |
| 插件平台 | X3 | 扩展创作工具而不侵入核心 | 生命周期、权限、API 版本、故障隔离 |
4.2 VM、脚本与网络运行时
| 模块 | 层级 | 业务价值 | 实现与追问点 |
|---|---|---|---|
| Edit VM | X2/X3 | 承载作者脚本和编辑服务 | 绑定编辑 World、进入试玩前释放、返回后重建 |
| Client VM | X3 | 承载本机玩家运行逻辑和表现 | 当前 Client World 生命周期、travel 清理、重建 |
| Server VM | X3 | 承载 DS 权威玩法 | 独立进程、权威状态、资源准入、服务端 API |
| VM 工厂与 generation | X3 | 防止旧 VM 回调污染新世界 | 角色、owner、递增代际、进程互斥、关闭屏障 |
| Lua/Luau 绑定 | X2/X3 | 将 C++ 引擎能力暴露为脚本 API | C 闭包、userdata、类型检查、所有权、析构 |
| 沙箱与 API 治理 | X3 | 在开放编程能力下控制安全和兼容 | 白名单、配额、权限、API 版本、错误隔离 |
| IRPC | X3 | 支持 Client/Server 脚本远程调用 | 端点、序列化、异步 future、上下文、状态码 |
| FlatBuffers/Protobuf 适配 | X2/X3 | 跨语言传递结构化数据 | Schema、宽整数、拷贝边界、兼容、大小限制 |
| 复制与属性同步 | X3 | 保持多端对象状态一致 | 权威、相关性、初始快照、增量版本、Dormancy |
| PlaySession 编排 | X3 | 启动 DS/Client、切换 VM 并恢复编辑 | 纯值上下文、进程管理、超时、统一退出事务 |
| 多关卡与 Teleport | X3 | 支持运行时跨世界和多实例 | 目标身份、载荷、预检、handoff、失败回源 |
| 跨 World 状态 | X3 | 在 World/VM 被销毁期间保留必要信息 | GameInstance 纯值、不得持有 Lua/World 引用 |
“三 VM”指三种角色,不代表三个 VM 同时存在于一个进程。编辑宿主加入试玩时,Edit VM 必须先释放,Client VM 才能创建;Server VM 位于独立 DS。这个边界是生命周期和安全模型,不只是目录拆分。
4.3 PixUI、页面与编辑器前端
| 模块 | 层级 | 业务价值 | 实现与追问点 |
|---|---|---|---|
| TypeScript/React 应用壳 | X1 | 统一启动、依赖和页面装配 | bootstrap、错误边界、状态 owner、可测试入口 |
| 组件与平台边界 | X1 | 隔离 PixUI 与标准浏览器差异 | adapter、受支持 DOM、输入、布局、降级 |
| 页面 Manifest/Registry | X1 | 用逻辑名而非文件路径路由页面 | entry、mode、layer、恢复策略、路径安全 |
| PageManager | X1 | 管理 replace、push、overlay 和返回栈 | pageId、generation、顺序、覆盖、恢复 |
| NativePageHost | X1 | 独占 PixUI View 的创建和销毁 | viewId、z-order、visible、interactive、幂等释放 |
| 页面上下文注入 | X1 | 给每个 JS 上下文稳定身份 | PageId、PageGeneration、平台、模式、DPI |
| Bridge Transport | X1 | 为 TS 提供类型化 send/subscribe | 消息类型、payload、unsubscribe、兼容层 |
| MessageRouter | X1 | 把消息路由到页面和领域 | 页面过滤、订阅作用域、domain 映射、释放 |
| PageRuntimeClient | X1 | 管理快照、增量和续订 | domain revision、旧消息拒绝、resume、dispose |
| 帧调度与合并 | X1 | 避免高频状态压垮 JS/渲染 | keyed scheduler、同帧合并、优先级、指标 |
| PixUI CLI/PFBS | X1 | 标准化开发、构建和运行时页面 | dev/build、固定产物、转换器、缓存、可重复 |
| 浏览器预览 | X1 | 缩短 UI 开发反馈周期 | mock transport、显式开发会话、环境隔离 |
| 输入与场景门控 | X1/X2 | 防止点击 UI 同时操作 3D 视口 | hover、focus、modal、同步矩形、C++ 前置拦截 |
| PixUI 兼容组件 | X1 | 处理非标准 DOM/布局行为 | 可控组件、重挂载、事件回退、焦点和文本刷新 |
4.4 数据、制品与资产
| 模块 | 层级 | 业务价值 | 实现与追问点 |
|---|---|---|---|
| 作者态 JSON | X2/X3 | 保留可编辑、可诊断的源数据 | Canonical 输出、未知字段、格式版本、迁移 |
| FlatBuffers Schema | X1/X2 | 提供紧凑、可校验的运行格式 | typed fields、扩展字段、默认值、Schema 演进 |
| QZBIN 容器 | X1/X2 | 封装二进制条目和压缩 | entry、版本、压缩、完整性、回读校验 |
| TypeHint | X1 | 在通用资产链路中选择正确解码器 | 类型枚举、材质变体、旧数据兼容、错误提示 |
| JSON 批量转换 | X1 | 迁移已有资产并验证覆盖 | 扫描、幂等、dry-run、失败清单、回滚 |
| 保存时机控制 | X1 | 避免编辑阶段被发布格式污染 | 作者保存与发布保存分离、能力开关、版本 |
| 冻结快照 | X1/X2 | 给制品构建提供不可变输入 | generation、文件清单、hash、临时目录、锁 |
| Artifact Inventory | X1 | 建立受信输入和逻辑路径 | 真实长度/hash、角色、owner、provider、路径安全 |
| Processor DAG | X1 | 让不同内容处理器可组合 | claim、优先级、依赖、并行、稳定错误 |
| 构建事务 | X1 | 防止失败留下可误用半成品 | 私有工作目录、整层提交、取消、清理 |
| Manifest 与 digest | X1 | 让制品身份可复现、可验证 | Canonical 排序、文件摘要、工具指纹、版本 |
| Verify | X1 | 独立确认产物未损坏或被替换 | 文件集、hash、容器结构、格式和能力验证 |
| Bundle/云资产 | X2/X3 | 分发模型、材质、纹理和其他依赖 | 内容身份、版本、缓存、依赖闭包、平台变体 |
| 角色/纹理预加载 | X1/X2 | 降低首见卡顿 | 静态依赖、材质贴图闭包、关键/后台优先级 |
4.5 多端构建、试玩与质量
| 模块 | 层级 | 业务价值 | 实现与追问点 |
|---|---|---|---|
| PC 编辑与试玩 | X1/X2 | 提供开发和创作主入口 | 编辑/试玩切换、子进程、资源 staging、恢复 |
| Android 构建与游玩 | X1 | 验证移动端真实内容运行 | 工程生成、包体、设备安装、启动参数、日志 |
| Android 调试工具 | X1 | 降低真机定位成本 | 设备选择、推包、拉日志、端口、错误归类 |
| Android 发布/试玩恢复 | X1 | 打通创作内容到真机试玩 | 发布版本、下载、入口参数、回退、清理 |
| iOS 构建 | X1 | 建立签名、编译和交付流水线 | 证书、Provision、远程构建、产物、设备验证 |
| 其他平台裁剪 | X2/X3 | 让同一内容在能力不同的平台运行 | 模块准入、无编辑目标、H5/小游戏边界、降级 |
| 构建配置与 BuildCell | X1 | 把本地步骤变为可复用流水线 | 输入参数、环境探测、缓存、超时、退出码 |
| 白盒编排 | X1 | 跨进程运行可重复端到端验证 | 场景、步骤、证据目录、超时、报告 |
| GAutomator 接入 | X1 | 使用统一自动化驱动游戏和 UI | provider、命令、稳定定位、Shipping 准入 |
| PixUI DOM 暴露 | X1 | 让自动化看到语义节点而非像素 | DOM 树、稳定 ID、可见性、坐标、动作 |
| 浏览器组件测试 | X1 | 快速验证前端状态和交互 | Vitest、Chromium、mock bridge、可重复 fixture |
| UE 自动化门禁 | X1 | 验证真实 PixUI/原生宿主集成 | 页面加载、消息、DOM、截图、性能证据 |
| 性能门禁 | X1/X2 | 防止框架重构引入首帧和交互退化 | 固定场景、帧耗、启动阶段、基线、证据归档 |
4.6 运行时内容能力
| 模块 | 层级 | 业务价值 | 实现与追问点 |
|---|---|---|---|
| 角色/Humanoid | X3 | 给创作者统一角色抽象 | 控制器、属性、状态、外观、网络身份 |
| 角色预设与外观 | X2/X3 | 降低角色配置成本 | 预设、覆盖、资源依赖、平台预算 |
| Animator/Track/Clip | X3 | 支持脚本化动画编排 | 轨道混合、时序、事件、网络同步、IK |
| 相机系统 | X3 | 支持不同玩法视角 | 模式、输入、遮挡、过渡、脚本 API |
| Ability/Skill | X3 | 提供可编程战斗能力 | 组件、槽位、预设、冷却、效果、revision |
| Behavior 系统 | X3 | 给 NPC 和对象可编排行为 | authoring transaction、黑板、调度、revision |
| NPC 与 AI | X3 | 支撑可创作角色和世界行为 | 控制、感知、导航、行为、性能预算 |
| 物理与碰撞 | X3 | 保证用户内容可运行 | 形状、材质、约束、网络、平台差异 |
| 游戏规则与阵营 | X3 | 支撑多人玩法基本结构 | 玩家关系、出生点、胜负、服务端权威 |
| UI/玩家界面 | X3 | 让创作者定义运行时交互 | GUI 对象、布局、事件、输入、安全区域 |
| 多层地图 | X3 | 支持公共层和多个关卡层 | 层身份、合并、发布条目、运行时切换 |
| 云资产运行时 | X3 | 按内容身份加载可复用资源 | 请求、缓存、校验、依赖、失败降级 |
五、TS、Lua、C++ 到底怎么通信
“PixUI 封装”太模糊。准确回答要先区分四条链。
5.1 TypeScript -> Lua:页面命令
React/TypeScript
-> typed command / transport.send(type, payload)
-> window.bridge.send
-> JSON envelope {type, seq, data}
-> PixUI official sendMessage / postMessage
-> C++ PixUI DelegateOnMessage / message forwarder
-> Lua callback
-> EditorService decode
-> MessageHandlers[type]
-> 编辑领域服务或 QZUGC C API前端只依赖 EditorTransport,不直接引用 Lua 函数或 C++ 类。类型化协议负责消息名和 payload;兼容 transport 把调用落到 PixUI bridge。C++ forwarder 把原生回调转入对应 Lua VM,Lua 服务再做解析、校验和业务分发。
为兼容不同 PixUI 运行环境,JS 侧除官方通道外还保留 postMessage 和 outbox 兜底。多通道的代价是可能重复,因此消息带序号,消费端必须去重。
5.2 Lua -> TypeScript:状态快照与增量
Lua domain state changes
-> PushToPixUI({type, data, meta})
-> JSON encode + monotonic seq
-> channel A: PixUIPostMessage
-> channel B: _qzugc.MsgQueue + MsgVersion
-> JS bridge dispatch + cross-channel seq dedupe
-> transport.subscribe
-> MessageRouter / PageRuntimeClient
-> React controller/store回程采用“原生消息 + 全局队列”双通道:原生通道低延迟,队列通道用于兼容和可靠兜底。JS 消费完整队列后回写 AckSeq,Lua 据此裁剪已确认消息;同一 seq 无论从哪条通道先到,只分发一次。高频属性更新还需要按帧合并,避免 JSON 编解码和 React 重绘放大。
5.3 Lua <-> C++:VM 内引擎绑定
C++ 在 QZUGC VM 的全局表注册 C 闭包。Lua 调用创建/销毁 PixUI View、切换可见和交互状态、发送消息、绑定回调、读写脚本全局等 API;C++ 实际持有原生 Widget、弱引用、delegate forwarder 和 Lua registry callback。
销毁时必须同时解除 Delegate、释放 registry reference、移除 UMG/Viewport 宿主并清理按 View 保存的对象。否则常见后果不是立刻崩溃,而是旧 View 回调写入新页面、Lua 关闭后异步回调重入,或 Widget 被错误保活。
5.4 Lua <-> Lua:Client/Server IRPC
UI bridge 和网络 RPC 是两套系统。Client/Server Luau 远程调用通过原生 IRPC 适配器、结构化序列化和异步客户端完成;每个主 Lua state 拥有独立的核心与序列化器。VM 关闭前先 detach 原生回调,异步完成也要经过 generation/owner gate,不能在 Lua heap 销毁后回调。
5.5 为什么还需要 pageId、generation、domain revision
仅有消息序号仍不够:
pageId区分逻辑页面实例。generation区分同名页面的第几次创建,旧 JS 上下文的迟到消息会被拒绝。domain把选择、属性、网格等状态分开订阅。revision在每个领域内单调递增,旧增量被丢弃,发现缺口可重拉快照。
页面 suspend 时释放传输订阅,但保留已接收 revision;恢复时带 revision 请求快照,从而只补缺失状态。dispose 则彻底释放 handler 和原生 View。
六、本人可以主讲的四组工作
6.1 页面协议与原生宿主
- 业务:编辑器页面从单个 HTML 演进为多页面、多层级、可恢复的工具应用。
- 实现:抽出 Manifest/Registry、PageManager、NativePageHost、PageRuntimeClient 和类型化 protocol;用逻辑名路由,用 replace/push/overlay 管栈;注入页面身份;按 generation/revision 拒绝旧消息;将 PixUI 差异收敛到 platform adapter。
- 难点:页面切换后原生 View、JS 上下文和 Lua 长生命周期服务不同步,最容易出现旧回调、错误恢复、重复订阅和输入穿透。
- 反思:页面生命周期必须成为协议的一部分,而不是 React 组件自己的
useEffect约定;native host 要成为唯一 View owner。
6.2 状态同步与 PixUI 性能
- 业务:对象树、属性和 Gizmo 会产生高频状态,若逐条跨语言推送,编辑器会卡顿且出现乱序。
- 实现:状态按 domain 切分,首次拉快照、后续接收 revisioned delta;按帧 key 合并高频更新;双通道共享序号并确认消费;页面卸载释放订阅。
- 难点:性能问题横跨 Lua 编码、C++ 消息、JS 解析、React 更新和 PixUI 绘制,不能只看一层耗时。
- 反思:先定义状态权威和一致性,再做批量、合并和增量;否则优化会把偶发错状态变成更难复现的问题。
6.3 ArtifactBuilder 与二进制化
- 业务:让作者源稳定转换为可发布、可验证、跨端一致的运行制品。
- 实现:冻结快照和文件清单;Builder 重读真实 size/hash;Processor 按角色 claim 文件并形成依赖 DAG;每个任务写私有事务目录,成功后稳定合并;最后生成 Manifest、ZIP 和独立 Verify 结果。材质等 JSON 通过 TypeHint、Schema 和批量工具迁移,且只在适当保存/发布阶段触发。
- 难点:临时目录、路径大小写、换行、工具版本、缓存和并发都会破坏确定性;失败产物不能被误识别为成功。
- 反思:构建系统最重要的不是“能打包”,而是输入可信、输出确定、失败无半成品、工具身份和产物都可验证。
6.4 多端构建与自动化
- 业务:让 UGC2.0 不只在开发机可运行,而能在 Android、iOS 和交付环境稳定构建、试玩和回归。
- 实现:把环境检测、工程准备、构建、签名、安装/启动和报告拆成可组合单元;接入 GAutomator 和白盒编排;PixUI 暴露 DOM 树和稳定 ID;测试从 TS 单测、Chromium 组件测试一直覆盖到 UE 和真机证据。
- 难点:平台错误经常表现为同一个“构建失败”,但根因可能在依赖、证书、脚本、资源、安装或运行入口。
- 反思:流水线要输出稳定 stage/errorCode 和保留局部证据,不能只回一个退出码;自动化定位符应表达业务语义,不依赖屏幕坐标和易变层级。
七、十二个必须能讲深的专题
7.1 Instance 对象模型
统一对象模型的价值是让编辑器、脚本、序列化和网络谈论同一个对象身份。类名说明能力,ObjectId 保证引用稳定,父子关系表达所有权,Property/Signal 提供行为接口。删除、复制和 Prefab 实例化都必须更新引用,不能把内存地址或页面节点当对象身份。
7.2 编辑态与试玩态隔离
作者数据可以转成运行输入,但 Edit VM、编辑 World、Lua 引用和回调不能直接带入试玩。宿主加入试玩时先保存纯值上下文并释放 Edit,再创建 Client;退出时销毁 Client 后重新构建 Edit。隔离的代价是恢复复杂,收益是生命周期清晰、运行环境可复现且不会把编辑权限带入游戏。
7.3 三 VM 与进程拓扑
VM role 和进程不是一一固定映射。Server 永远在 DS;Client 可以在宿主或独立客户端;某些测试模式下宿主保留 Edit、Client 全部在子进程。回答时先说明测试模式、宿主是否加入和是否跨关卡,再谈进程数量,不能死背“永远三个 VM”。
7.4 页面生命周期协议
逻辑页面有 created、active、suspended/covered、disposed;原生 View 由 host 独占。push 时旧页可以隐藏或只保留渲染但禁用交互,back 时恢复;replace 必须释放旧 View;overlay 不破坏主栈。每次创建分配新 generation,从根上拒绝迟到消息。
7.5 跨语言消息可靠性
消息协议至少需要类型、payload、序号、页面身份和状态版本。多通道提高兼容性,也带来去重和确认责任。大消息、高频消息和页面销毁是三个主要故障源;因此需要队列上限、Ack、按帧合并、旧代际过滤和统一 dispose。
7.6 快照与 revisioned domain
状态按领域拆分后,每个 domain 自己维护 revision。首次订阅请求快照,增量只接受更高版本;页面暂停时记住 revision,恢复后从该点续订。这样选择变化不会迫使属性和网格一起全量刷新,也能明确是哪一个领域发生了版本缺口。
7.7 作者源与发布制品
作者源追求可编辑、可诊断和向前兼容;发布制品追求紧凑、快速和不可变。二者不能互相覆盖。二进制化应位于明确的保存/发布边界,通过 Schema 和版本演进,而不是编辑时悄悄把 JSON 改成运行格式。
7.8 确定性构建
相同输入、工具版本和配置应产生相同 Manifest 与文件集。路径规范化、排序、hash、Processor DAG、稳定错误选择和事务合并都服务于确定性。并发只允许改变完成时间,不能改变输出顺序和根错误。
7.9 跨端能力裁剪
共享内容语义不等于每个平台装载相同模块。无编辑目标不应带作者运行时,Server 不需要 UI,移动和小游戏有自己的资源、进程和调试限制。应通过模块准入和 capability 描述裁剪,而不是到处用平台 if 修补。
7.10 UI 自动化语义树
PixUI 页面若只暴露像素,自动化只能靠坐标和截图,极易受分辨率和布局影响。正确做法是导出带稳定 ID、角色、状态、可见性和边界框的语义树,再由 provider 映射点击、输入和查询;Shipping 是否开放必须有显式准入和安全边界。
7.11 性能诊断
编辑器卡顿可能来自 Lua 状态生成、JSON 编码、原生传输、JS 解析、React diff 或 PixUI 绘制。诊断需要同一个消息或帧的跨层关联标识,并把启动、首帧、交互和高频拖拽分开测。没有固定场景和证据门禁的“体感变快”不能作为结论。
7.12 旧内容与协议演进
Schema 新增字段要有默认值,删除字段要保留读取窗口,未知字段尽量透传。协议可以忽略未知字段以向前兼容,但路径逃逸、类型错误、资源超限等安全条件必须拒绝。迁移工具要 dry-run、幂等、输出失败清单,并能定位源版本和目标版本。
八、面试回答模板
8.1 “请描述 UGC2.0 客户端架构”
我会从创作内容如何进入运行时来讲。最上层是 TypeScript/React 的创作界面;下面是页面协议和 PixUI 原生宿主,负责页面栈、生命周期和跨语言消息;编辑领域层负责选择、Gizmo、属性、事务、撤销和 Prefab;核心数据由 DataModel/Instance、Property、Signal 和 Service 组成,脚本通过 Luau VM 与 C++ binding 访问;试玩时 Edit、Client、Server 是独立角色和生命周期,服务端保持权威;保存发布侧把作者 JSON、脚本和资产冻结成快照,经 Processor DAG 转成带 Manifest 的可验证 Artifact;最后由多端构建、缓存、自动化和性能门禁保证交付。核心边界是对象身份、VM 隔离、页面代际和作者源/发布制品分离。
8.2 “你在 UGC2.0 做了什么”
我主要做了四块。第一是 PixUI 页面基础设施,把 TypeScript 页面、Lua 编辑服务和 C++ 原生 View 之间的协议、页面栈、生命周期和状态版本补齐;第二是 ArtifactBuilder 和 JSON/FlatBuffers/QZBIN 二进制化接入,解决冻结输入、处理器编排、校验和失败清理;第三是 Android、iOS 的构建、试玩恢复和调试工具;第四是 GAutomator、PixUI DOM、稳定 ID 和白盒流水线。对象模型、三 VM 和完整运行时不是都由我设计,但这些是我的上下游,我已经结合源码系统复盘。
8.3 “PixUI 封装里 TS、Lua、C++ 怎么通信”
前端不是直接调用 C++。TS 先调用类型化 transport,bridge 把命令编码成带 type、seq 和 data 的 JSON,通过 PixUI 官方消息通道送到 C++;C++ 的 message forwarder 再进入当前 Edit VM 的 Lua callback,由 EditorService 解码并分发到领域 handler。回程由 Lua 给消息加 seq、pageId、generation、domain 和 revision,优先走原生 PostMessage,同时写全局队列做兼容兜底;JS 对两条通道按 seq 去重,消费队列后回写 Ack。Lua 调 C++ 则是另一层:C++ 在 VM 注册 QZUGC C API,Lua 用它创建/销毁 View、绑定回调和读写 PixUI 全局。Client/Server 之间又是独立的 IRPC,不和 UI bridge 混用。
8.4 “为什么要做 page generation 和 revision”
generation 解决对象生命周期,revision 解决状态顺序。页面关闭再打开后,同名页面已经是新的 JS 上下文,旧异步消息必须按 generation 拒绝;同一页面里选择、属性、网格等领域各有 revision,只接受更高版本,暂停恢复时带上最后版本重新请求快照。二者缺一,都会出现旧页面覆盖新页面或乱序增量覆盖新状态。
8.5 “为什么不让 TS 直接调 C++”
直接绑定会把页面生命周期、引擎对象和业务接口耦在一起,也难以做浏览器预览和协议测试。现在 TS 只依赖稳定 transport,Lua 拥有编辑领域编排,C++ 拥有原生资源和引擎能力。代价是序列化和协议治理成本,因此需要类型定义、版本、批量、可观测和自动化测试来控制。
九、个人能力收口
UGC2.0 最能证明四种能力:
- 能把跨语言 UI 从“能发消息”提升为有身份、生命周期、版本和恢复能力的运行协议。
- 能设计作者源到发布制品的确定性流水线,处理并发、失败、路径和兼容边界。
- 能跨 TypeScript、Lua、C++、Python 和构建系统定位问题,而不是只守一层代码。
- 能把浏览器测试、UE 自动化和真机构建串成分层证据链。
暂时不能使用的说法:
- 我主导了 UGC2.0 全部对象模型和三 VM 架构。
- 所有运行时、网络、Prefab、云资产和玩法能力都是我做的。
- PixUI bridge 保证 exactly-once;现有机制是多通道去重与确认,不是分布式意义的 exactly-once。
- 没有基线报告时声称明确性能提升百分比。
后续专题文档应从本篇拆出:UGC2.0 架构背诵稿、跨语言通信追问卡、页面生命周期 STAR、ArtifactBuilder STAR、多端构建 STAR、UI 自动化 STAR 和三 VM 设计题。