UGC1.0 地图数据与发布:从快照到审核上线

这篇回答 UGC 平台最基础也最容易被低估的问题:一张正在编辑的地图,怎样变成可下载、可审核、可回滚、可运行的线上版本。

面试官:你在 UGC1.0 的地图数据链路做了什么?

30 秒回答

我早期直接负责过地图模型、封面图、上传下载和发布链路,后续又做了多文件地图数据的压缩、加密、上传下载以及地图大小治理。我的理解是,地图保存不是写一个文件,发布也不是再调一次上传接口。它们是一条版本化事务:先冻结编辑快照,校验 Schema 和依赖,再按清单序列化、压缩加密、用 MD5 避免重复上传,最后提交审核并生成线上版本。失败只能影响本次任务,不能覆盖上一个成功版本。

90 秒回答

一张 UGC 地图至少包含场景对象、逻辑、层级数据、资源引用、封面和发布说明。早期单文件容易实现,但地图变大后,任何小改动都可能重新序列化和上传全部内容,也不利于定位坏档。因此系统逐步转向多文件交付:根据明确文件清单收集数据,保持归档路径,异步压缩并加密,上传时用内容摘要识别未变化文件;下载后再校验、解密、解压和加载。

发布侧还要串起试玩或预检、封面采集、文本与图片审核、资源权限、上传和发布状态。这里最重要的设计是“作者源、发布快照、线上制品”三者分离:创作者可以继续编辑,但本次发布始终面向冻结输入;审核中和已上线版本也有独立身份。我的直接工作集中在客户端地图与交付链路,完整审核服务和全部资源平台是协作上下游。

面试官:地图数据应该怎样分层?

直接回答

我会分成四类,而不是把所有内容塞进一个大对象:

数据例子关键要求
结构数据对象身份、父子关系、类型、属性稳定 Schema、确定性序列化、版本迁移
逻辑数据元件连接、脚本、变量、任务规则引用完整、运行域明确、安全校验
资源数据图片、模型、音频、材质、预制体稳定资源 ID、版本、权限、平台变体
发布元数据标题、说明、封面、玩法标签、版本审核状态和线上版本可追溯

地图正文只保存稳定引用,不保存开发机本地路径。资源文件和结构数据可以拆分交付,但必须由同一 manifest 描述它们属于哪个地图快照。

面试官:为什么要做多文件地图?

单文件的优点是原子性直观,但随着地图增大,会出现四个问题:保存与上传放大、局部损坏难定位、资源无法独立缓存、多人或分层编辑难拆分。多文件可以按场景层、逻辑域或资源类别组织,使未变化内容复用已有版本。

代价是完整性问题从“一个文件是否存在”升级为“整组文件是否属于同一个版本”。因此必须增加:

  • manifest:文件逻辑名、归档路径、大小、摘要、版本和可选性。
  • 快照 ID:阻止混用不同保存批次的文件。
  • 原子提交:只有必需文件全部可用,快照才可见。
  • 缺失诊断:明确缺哪个文件、哪个依赖、属于哪个阶段。
  • 兼容规则:旧版本未知字段、缺省字段和逐级迁移策略。

面试官:多文件是怎样打包和上传的?

项目中我做过按文件列表和目录规则异步压缩,并把压缩与加密串起来。抽象后的链路是:

flowchart LR
    SNAP["冻结地图快照"]
    LIST["生成文件与目录清单<br/>逻辑路径 / 摘要 / 版本"]
    ZIP["异步压缩指定文件<br/>汇报文件级进度"]
    ENC["加密临时归档"]
    DIFF["与云端摘要比较<br/>筛出变化文件"]
    UP["上传制品"]
    META["提交地图版本与 Manifest"]

    SNAP --> LIST --> ZIP --> ENC --> DIFF --> UP --> META

归档时必须区分源文件路径和 archive path。前者只在本机有效,后者决定下载解压后的逻辑布局。上传成功后再提交版本元数据,避免服务先看到一个引用不完整的地图。

面试官:MD5 去重是不是就能保证数据正确?

不能。摘要在这里主要用于内容寻址、变化检测和传输校验,不等同于业务完整性,也不替代安全签名。

正确流程是先在冻结快照上计算摘要,用它判断内容是否变化;上传后校验服务端记录或返回;manifest 还要校验文件数量、必需项、Schema 和资源引用。即使每个文件摘要都正确,也可能把不同快照的文件拼到一起,所以还需要版本或快照身份。

面试官:为什么压缩和加密要用临时文件?

因为最终路径应只出现完整产物。先写临时文件,压缩成功后再加密到目标,全部成功后原子替换或提交;任一步失败都删除临时文件。若直接覆盖正式文件,中途崩溃可能留下“路径存在但内容不完整”的假成功。

异步对象还要持有到回调完成。取消或页面退出时不能立即释放后台仍在使用的压缩器,也不能让旧任务回调更新新任务进度。

面试官:快速连续保存为什么容易失败?

如果两个保存任务同时读取可变编辑态,它们可能共用临时目录、覆盖进度、交叉更新 MD5 或让较早任务最后提交,导致线上版本倒退。修复不能只靠禁用按钮,而应在领域层串行化同一地图的提交。

一种稳妥设计是:

编辑操作持续写入 Working Copy
  -> Save 请求生成 Snapshot N
  -> Snapshot N 进入单地图任务队列
  -> 后续 Save 若内容相同则合并;不同则生成 Snapshot N+1
  -> 只有任务拥有提交令牌时才能更新远端版本指针

页面按钮可以防误触,但任务队列、快照身份和提交序号才是正确性保证。

面试官:保存、自动保存和发布有什么区别?

操作目标是否必须审核失败影响
撤销/重做回退一次编辑意图否当前编辑事务
自动保存防止本地或会话数据丢失否最近恢复点
云端草稿保存跨设备继续编辑通常不进入公开审核草稿版本
发布生成可分发、可运行版本是本次发布任务,旧线上版保持不变

它们可以共享 Schema、脏标记和序列化能力,但不能共用一个粗糙的“保存成功”布尔值。

面试官:完整发布状态机怎么画?

Editing
  -> FreezeSnapshot
  -> Validate
  -> CaptureCover
  -> SerializeAndPackage
  -> UploadArtifacts
  -> SubmitReview
  -> WaitingReview
  -> PublishVersion
  -> Published

任一步 -> Failed / Cancelled
       -> 保留上一线上版本
       -> 记录可重试阶段与错误

预检应该尽量放在昂贵操作之前。Schema 错误、资源缺失、超过硬上限和必崩问题直接阻断;性能建议或非关键质量问题可以警告。上传成功但提交审核失败时,已上传的不可变制品可以在有效期内复用,不必每次全部重传。

面试官:发布前为什么要进入试玩或拍照状态?

封面需要反映运行时可见结果,而不是编辑器中的 Gizmo、选中框和隐藏规则。项目早期做过发布前截图、相机移动、运行状态切换以及 Android/iOS 图片方向和黑图问题治理。

正确做法是把拍照建模成独立状态:保存当前编辑上下文,切换到受控预览状态,冻结编辑输入,等待必要资源和渲染稳定,再采集图片,最后无论成功失败都恢复相机、对象可见性和输入。不能用若干 UI 显隐临时拼出拍照模式。

面试官:文本、图片、模型和脚本的安全审核一样吗?

不一样,它们的成本和风险不同:

内容客户端前置检查平台审核重点运行时防线
文本长度、编码、空值、明显非法字符敏感语义与上下文展示转义、举报和下架
图片格式、尺寸、透明度、文件大小图像内容安全审核状态、替换和缓存失效
模型/资源格式、依赖、数量、容量版权、恶意资产和质量资源预算、白名单、隔离加载
脚本语法、API、依赖权限和恶意行为策略沙箱、配额、服务端校验、异常隔离

客户端检查的价值是尽早反馈和节省上传成本,但客户端不可信,不能承担最终安全裁决。审核结果也不是一个永久布尔值,而应绑定资源版本和策略版本。

面试官:云端资源怎么管理?

地图应保存 资源 ID + 版本或版本约束 + 用途,资源平台管理文件清单、审核态、权限和平台变体。下载缓存键至少包含资源身份、版本和平台,不能只用文件名。

发布地图前需要遍历依赖图:资源是否存在、当前作者是否有权限、审核是否通过、目标平台产物是否齐全、引用是否形成循环。资源删除也必须查询引用者,选择阻断删除、替换引用或固定旧版本,而不是普通 CRUD。

面试官:下载和加载怎样保证不产生坏地图?

下载先进入临时目录,按 manifest 拉取和校验全部必需文件,再解密解压到新版本目录。加载前验证 Schema 与资源引用,成功后原子切换“当前版本”指针。旧版本在新版本验证完成前不能删除,这样失败时仍可回退。

对部分可选资源可以降级,但结构文件或关键逻辑缺失必须失败。错误信息要包含地图版本、文件逻辑名、阶段和原因,不能只有“加载失败”。

面试官:怎样做版本兼容?

读取时先识别 Schema 版本,再按 v1 -> v2 -> v3 逐级迁移到当前内存模型。每步迁移必须幂等、有测试样例,并保留未知字段或给出明确丢弃策略。写出时只由当前版本序列化器产生确定结果。

批量治理旧地图时先用离线解析工具扫描,不直接在用户首次打开时赌一次迁移。遇到无法迁移的数据,可以只读打开、提示修复或保留旧运行时,而不是写回一个半迁移文件。

面试官:你怎样验证这条链?

数据测试

  • 当前版本往返序列化结果一致,输出顺序确定。
  • 每个历史 Schema 都有迁移样例,重复迁移不改变结果。
  • 缺文件、坏摘要、错误密钥、截断包和未知字段有明确诊断。
  • 多次保存、取消、崩溃恢复和任务乱序不会倒退版本。

发布测试

  • 封面失败、上传部分成功、审核拒绝和轮询超时可恢复。
  • 发布期间继续编辑,不会改变本次冻结快照。
  • Android、iOS 和 PC 的图片方向、格式与目标制品一致。
  • 旧线上版本在新版本失败时仍可进入和游玩。

项目提交能证明我长期处理了这些链路和问题,但缺少统一的成功率、节省流量和发布耗时报告,所以目前不对外给收益百分比。

面试官:你个人负责和团队能力的边界是什么?

我直接负责或长期投入过地图模型、封面采集、上传下载、MD5 去重、多文件压缩加密、地图大小治理以及多端发布问题。云端资源库、审核服务和平台级质量门禁是协作系统;我做过客户端接入和问题闭环,也能解释完整设计,但不会说成整个平台都由我实现。

快速背诵版

我把 UGC 地图交付理解为版本化事务,而不是文件上传。编辑阶段先冻结不可变快照,按 manifest 序列化场景、逻辑和资源引用;多文件按逻辑归档路径异步压缩加密,用摘要做变化检测和传输校验;完整产物上传后才提交审核与发布版本。封面、文本、图片、资源和脚本走各自检查,客户端负责前置校验与体验,服务端负责最终安全。失败时本次任务可重试,上一线上版本不受影响。我的直接工作覆盖地图模型、封面、上传下载、多文件链路和大小治理,平台审核和资源服务是协作边界。

责任边界

内容面试表述
地图模型、封面、上传下载与多文件交付可说“我直接负责/长期投入”
压缩加密、MD5 去重与地图大小治理可说“我实现或推进过”
完整云资源平台与审核服务说“上下游协作和客户端接入”
当前团队源码中的所有发布能力说“项目体系/源码复盘”,不冒充个人交付
流量、耗时和成功率提升无统一报告前不报百分比

关联阅读