Files
XCEngine/docs/used/Library资产导入与缓存系统收口计划_完成归档_2026-04-03.md

20 KiB
Raw Permalink Blame History

Library资产导入与缓存系统收口计划

归档状态2026-04-03当前 project 范围内的 Library 导入与缓存系统收口已完成,本文档转为归档记录。

0. 文档定位

这份文档不是上一轮“从零搭一套 Unity 式 Library 体系”的继续描述,而是当前阶段的正式收口文档。

0.1 当前执行进度2026-04-03

阶段 状态 当前结果
阶段 A协议定稿与旧兼容删除 已完成 已删除 mesh= / materials= 旧兼容读取,项目资产序列化正式收敛到 AssetRef路径字段仅保留给虚拟资源scene 迁移工具链已移除。
阶段 B导入与缓存边界收口 已完成 AssetImportService 已接管 Library 根目录、快照构建、缓存重建与 artifact 保证入口;ProjectAssetIndex 已只消费服务快照;ResourceManager 已收口为运行时缓存/异步调度入口,并提供 RefreshProjectAssets / RebuildProjectAssetCache
阶段 C进行中 已完成 xcmat 纹理绑定的 AssetRef + lazy resolve 首轮收口;下一步继续压缩缓存命中后的恢复成本,并检查是否还存在主线程等待点。
阶段 D最小工具闭环 已完成 已完成 Reimport Selected Asset / Reimport All Assets / Clear Library 正式入口;已补 Project 面板最小导入状态输出;已接入 orphan artifact 清理。

0.2 当前已完成的收口结果2026-04-03

  • 阶段 A 已完成并验证通过:
    • MeshFilterComponent 对项目 mesh 只序列化 meshRefmeshPath 只保留给 builtin://...
    • MeshRendererComponent 对项目 material 只序列化 materialRefsmaterialPaths 只保留给 builtin://...
    • 旧的 mesh= / materials= 兼容读取已移除
    • scene 迁移命令、菜单、report 链路已删除
  • 阶段 B 已完成并验证通过:
    • AssetImportService 对外新增 LookupSnapshotImportedAssetGetLibraryRoot()RebuildLibraryCache()
    • ProjectAssetIndex 不再直接拼装 AssetDatabase 细节,而是只刷新服务快照
    • ResourceManager 不再暴露旧式导入数据库心智,新增 RefreshProjectAssets()RebuildProjectAssetCache()GetProjectLibraryRoot()
    • AssetDatabase 初始化后会落盘 ArtifactDB/artifacts.db,使空 Library 结构稳定成型
  • 阶段 C 已开始并完成首个子项:
    • Material 纹理绑定新增稳定 AssetRef 元数据,运行时按需把 AssetRef 解析为加载路径
    • xcmat 协议已升级为纹理绑定写入 AssetRef + load path hint
    • AssetDatabase importer version 已提升,旧 material artifact 将自动失效并重建
  • 阶段 D 已开始并完成首轮工具口:
    • AssetDatabase 已新增 TryGetImportableResourceType()ReimportAsset()ReimportAllAssets()
    • AssetImportService 已新增 ClearLibraryCache()ReimportAllAssets()ReimportAsset()
    • ResourceManager 已新增 CanReimportProjectAsset()ReimportProjectAsset()ClearProjectLibraryCache()
    • editor Assets 菜单已新增 Reimport Selected AssetReimport All AssetsClear Library
    • AssetImportService 已新增导入状态快照,Project 面板工具栏会显示最近一次导入/清库/清理状态
    • AssetDatabase 已新增 orphan artifact 清理,Refresh / Reimport / 自动重导入 后都会回收未被 ArtifactDB 引用的 Library/Artifacts/* 目录
  • 已完成 focused 验证:
    • asset_tests
      • ResourceManager_Test.ConcurrentAsyncLoadsCoalesceSameMeshPath
      • ResourceManager_Test.AssetLookupFallbackRefreshesSnapshotForNewProjectAsset
      • ProjectAssetIndex_Test.RefreshesSnapshotThroughImportServiceOnCacheMiss
      • AssetImportService_Test.RebuildLibraryCacheKeepsStableAssetRefs
      • ResourceManager_Test.RebuildProjectAssetCacheRefreshesLookupState
      • AssetImportService_Test.ClearLibraryAndReimportAllAssetsManageArtifactsExplicitly
      • AssetImportService_Test.ImportStatusTracksExplicitOperationsAndRefreshCleanup
      • ResourceManager_Test.ReimportProjectAssetBuildsArtifactForSelectedPath
    • editor_tests
      • EditorActionRoutingTest.ProjectCommandsExposeAssetCacheMaintenanceActions
      • EditorActionRoutingTest.ProjectCommandsReimportSelectedAssetAndClearLibraryDriveAssetCache
      • EditorActionRoutingTest.ProjectCommandsReportWhenScriptAssembliesCanBeRebuilt
    • components_tests
      • MeshRendererComponent_Test.SerializeAndDeserializeLoadsProjectMaterialByAssetRef
      • MeshRendererComponent_Test.DeferredSceneDeserializeLoadsProjectMaterialAsync
    • material_tests46/46 通过
    • mesh_tests33/33 通过
    • scene_tests
      • Scene_ProjectSample.DeferredLoadBackpackSceneEventuallyRestoresBackpackMesh
      • Scene_ProjectSample.DeferredLoadBackpackSceneEventuallyProducesVisibleRenderItems
    • XCEditor Release 已成功编译

旧方案文档已经归档到:

  • docs/plan/used/Unity式Library资产导入与缓存系统重构方案.md

归档原因很简单:

  • 旧文档解决的是“从没有 Library到建立 Library 基础设施”的问题。
  • 现在的问题已经不是“要不要做 Library”而是“怎么把当前这套半过渡、半正式的实现收成一套干净的正式系统”。

本轮收口以以下前提为准:

  • 只服务当前 project 这一个项目。
  • 不兼容旧版本 scene / component 资产引用格式。
  • 不再提供旧格式迁移工具。
  • 可以直接改写 project 下现有场景和资源源文件。
  • 目标不是继续堆补丁,而是形成一套边界清晰、行为稳定、可长期维护的正式实现。

1. 当前收口基线

当前系统已经具备以下基础,这些不是本轮要推倒重来,而是本轮收口的起点:

  • 已有 Unity 风格的 Library 目录结构:
    • Library/SourceAssetDB
    • Library/ArtifactDB
    • Library/Artifacts
  • 已有 .meta + AssetGUID 机制,项目资产已经具备稳定身份。
  • 已有 AssetRef 结构,运行时已经可以通过 AssetRef 回查项目资产。
  • 已有纹理、材质、模型 artifact
    • xctex
    • xcmat
    • xcmesh
  • 已有 AssetImportService,用于承接导入与 artifact 保证逻辑。
  • 已有 ProjectAssetIndex,用于承接项目资产路径与 AssetRef 快照索引。
  • ResourceManager 已不再直接承担全部导入数据库职责,而是开始回到运行时调度器角色。
  • scene 打开链路已经接入 deferred restoreMeshFilterComponent / MeshRendererComponent 能在反序列化后异步恢复项目资源。
  • 当前 project/Assets/Scenes/Main.xcproject/Assets/Scenes/Backpack.xc 已经具备 AssetRef 版本数据,可作为最终格式收口的直接修改对象。

当前真正没有收口的,不是“功能不存在”,而是下面这三类问题还在:

  • 还保留着旧格式兼容和双写逻辑。
  • 组件 / scene / editor 工具链里还残留过渡期代码。
  • 材质与贴图恢复仍不够轻,缓存命中后仍有额外同步成本。

2. 本轮收口的核心原则

2.1 不保留旧版本兼容

这是本轮与上一轮最大的区别。

本轮明确不做以下事情:

  • 不兼容历史 mesh= / materials= 场景字段。
  • 不兼容“项目资产仍按普通文件路径序列化”的旧格式。
  • 不保留 path + AssetRef 双写作为长期状态。
  • 不保留 Migrate Scene AssetRefs 之类的迁移工具与菜单。

允许保留的只有两类稳定引用:

  • AssetRef
    • 用于 project/Assets 下的正式项目资产。
  • builtin://...
    • 用于内置几何体、内置默认材质等虚拟内置资源。

这里的 builtin:// 不是旧版本兼容,而是引擎内部稳定资源协议,可以继续保留。

2.2 只对当前项目做干净落地

因为当前只服务一个项目,所以这轮不需要为了“以后可能导入旧项目”保留复杂迁移链路。

本轮允许直接做以下事情:

  • 直接改写 project/Assets/Scenes/*.xc
  • 直接删除旧序列化字段的读写逻辑
  • 直接删除旧迁移命令、菜单、报告结构
  • 直接调整测试数据到最终格式

2.3 运行时只负责“用缓存”,不负责“解释历史”

收口完成后,运行时层要满足:

  • scene 反序列化只恢复最终格式数据
  • ResourceManager 只做运行时缓存、异步调度、artifact 读取入口
  • 导入与索引职责留在 AssetImportService / ProjectAssetIndex
  • 不再在运行时主链路里背负旧协议兼容判断

2.4 收口优先级高于“继续设计更大系统”

本轮目标是把现有系统收干净,不追求继续扩成更庞大的框架。

因此本轮只做两件事:

  • 删除过渡态
  • 补齐正式版闭环

不在本轮追求:

  • prefab 全面资产管线化
  • 动画、音频、shader 全类型导入器
  • 远程缓存
  • 多项目兼容框架
  • 一步到位把所有内部类都拆到最细

3. 收口后的目标形态

3.1 最终数据协议

收口后scene / component 的资产引用协议定为:

  • 项目 mesh只写 meshRef
  • 项目 material只写 materialRefs
  • 内置 meshmeshPath=builtin://...
  • 内置 materialmaterialPaths=builtin://...

不再允许以下状态作为正式协议存在:

  • 项目资产依旧只存普通文件路径
  • 项目资产同时写路径和 AssetRef
  • 反序列化时优先猜测旧字段再兜底

3.2 最终运行时边界

收口后各层职责如下:

  • AssetImportService
    • 工程扫描
    • .meta 管理
    • SourceAssetDB / ArtifactDB 维护
    • EnsureArtifact
    • Refresh
    • Reimport / Clear Library 入口
  • ProjectAssetIndex
    • 项目资产路径快照
    • AssetRef <-> 项目路径 映射
    • 项目资产查找缓存
  • ResourceManager
    • runtime object cache
    • async load coalescing
    • artifact runtime load dispatch
    • deferred scene load 控制
  • Component / Scene
    • 只保存最终资产引用
    • 不承担旧协议迁移职责

3.3 最终用户行为

收口后应达到以下体验:

  • 第一次导入可能慢,但之后再打开同一个 scene不应再同步重跑原始 obj/png/jpg 导入。
  • 打开含有大型 OBJ 的 scene 时,不应长时间卡死 editor 主窗口。
  • 命中 artifact 后mesh/material 恢复应尽量走异步路径。
  • 关闭 editor 再打开后,项目资产引用应稳定恢复,不出现“模型丢失、材质丢失、内置 sphere 丢失”这类状态回退问题。
  • 用户能明确知道当前是“命中缓存”还是“正在导入/重建缓存”。

4. 本轮必须删除的过渡态

这部分是收口计划的关键,不删掉这些内容,系统就始终处于过渡状态。

4.1 删除旧序列化兼容

目标:

  • 删除 MeshFilterComponent 对旧 mesh= 字段的长期兼容读取。
  • 删除 MeshRendererComponent 对旧 materials= 字段的长期兼容读取。
  • 删除“项目资产 path 与 AssetRef 双写”的长期行为。

允许保留:

  • builtin:// 的显式处理。

禁止保留:

  • “先读 path不行再猜 AssetRef
  • “为了兼容老场景继续支持项目文件路径”

4.2 删除场景迁移工具

以下过渡期工具应整体移除:

  • Migrate Scene AssetRefs 菜单项
  • 对应 action / command / project manager migration report
  • 专门为旧场景迁移设计的 editor 流程

原因:

  • 当前项目只有一个,已有 scene 可以直接重写。
  • 继续保留迁移工具,只会让新系统一直背着旧协议。

4.3 删除长期双轨测试

需要同步清理测试中的过渡态假设:

  • 旧格式 scene 兼容测试
  • 双写格式测试
  • 迁移工具测试

替换成正式版测试:

  • 最终 scene 协议测试
  • 关闭 editor 重开后的稳定恢复测试
  • artifact 命中路径测试
  • 异步恢复与渲染可见性测试

5. 本轮必须补齐的正式能力

5.1 材质与贴图真正 lazy 化

当前模型 artifact 虽然已经存在,但材质恢复后仍然容易把关联贴图一起拉进来,导致:

  • 场景虽然不在反序列化阶段阻塞
  • 但资源真正恢复时仍然偏重

本轮必须补齐:

  • xcmat 成为正式稳定 artifact
  • Material 运行时对象只持有 texture AssetRef
  • texture runtime handle 按槽位、按需解析
  • mesh 恢复不顺手触发整套材质贴图同步加载

这是“缓存命中了但还是觉得重”的核心收口项。

5.2 明确导入与运行时边界

虽然最近已经引入:

  • AssetImportService
  • ProjectAssetIndex

但本轮要进一步明确:

  • ResourceManager 外部不再暴露旧式导入心智
  • 项目资产查找统一经过 ProjectAssetIndex
  • artifact 生成统一经过 AssetImportService
  • AssetDatabase 作为底层实现细节继续收口到 service 后面

本轮的目标不是一定把 AssetDatabase 拆成三个类,而是先把“对外边界”收干净。

也就是说,本轮要求:

  • 类内可暂时还偏胖
  • 但对外职责必须已经清晰

5.3 缓存运维闭环

正式版至少要有以下最小运维能力:

  • 单资源 Reimport
  • Reimport All
  • Clear Library
  • 项目启动时检查并重建缺失缓存
  • 删除源资源后识别 orphan artifact

如果这些没有,系统虽然能工作,但一旦缓存脏掉就难以恢复,仍然不算收口。

5.4 可观测性闭环

本轮至少要做到用户能看见:

  • 当前资源是命中 artifact 还是触发重导入
  • 正在导入哪个资源
  • 导入失败原因
  • scene 正在等待哪些资源恢复

不要求本轮先做完整面板,但至少要把日志、状态文案、必要的调试输出整理成稳定可用的最小版本。


6. 实施阶段

阶段 A协议定稿与旧兼容删除

目标

把当前半兼容、半正式的 scene / component 数据协议收成最终格式。

任务

  • MeshFilterComponent
    • 项目资产只写 meshRef
    • 只对 builtin:// 保留 meshPath
    • 删除旧 mesh= 历史兼容读取
  • MeshRendererComponent
    • 项目资产只写 materialRefs
    • 只对 builtin:// 保留 materialPaths
    • 删除旧 materials= 历史兼容读取
  • 直接改写 project/Assets/Scenes/Main.xc
  • 直接改写 project/Assets/Scenes/Backpack.xc
  • 如果项目里还有其他 scene / snapshot / prefab 使用旧项目资产路径,一并直接改成最终格式

同步删除

  • Migrate Scene AssetRefs action
  • ProjectCommands 中对应 migration command
  • ProjectManager 中对应 migration report / migration logic
  • 相关测试

阶段完成标准

  • 项目场景中不再存在旧项目资产路径协议
  • engine/editor 中不再存在迁移工具入口
  • 组件反序列化代码只处理最终协议与 builtin 协议

阶段 B导入与缓存边界收口

目标

Library 系统对外呈现为一套明确的正式接口,而不是几个类拼在一起的过渡实现。

任务

  • 把项目资产索引访问统一走 ProjectAssetIndex
  • 把 artifact 生成与保证统一走 AssetImportService
  • 收敛 ResourceManager 中剩余的导入数据库耦合
  • 梳理 AssetDatabase 内部接口,限制它作为 service 内部实现使用
  • 增加明确的 Refresh / Reimport / Clear Library 入口

阶段完成标准

  • editor / runtime 外部调用时,心智模型已经稳定为:
    • 找项目资产:ProjectAssetIndex
    • 产出或校验 artifactAssetImportService
    • 取 runtime objectResourceManager

阶段 C性能闭环

目标

把“看起来已经异步,但恢复仍然偏重”的成本继续压下去。

任务

  • 材质贴图 lazy resolve
  • 减少 mesh 恢复时顺手加载整套关联资源
  • 校验首次导入、二次打开、关闭重开三种路径的时间差异
  • 清理仍可能在主线程触发的大锁与同步等待点
  • 必要时加入轻量 placeholder / loading state 文案

阶段完成标准

  • 含 OBJ 的 scene 再次打开时editor 主窗口不出现长时间假死
  • artifact 命中时恢复成本显著低于首次导入
  • 关闭 editor 重开后的恢复链路仍然稳定

阶段 D最小工具闭环

目标

把这套系统变成“可维护”的,而不是只能靠调试日志救火。

任务

  • 已完成:增加 Reimport Asset
  • 已完成:增加 Reimport All
  • 已完成:增加 Clear Library
  • 已完成:增加最小导入状态输出
  • 已完成:增加 orphan artifact 清理

阶段完成标准

  • 用户可以主动重建缓存
  • 缓存脏掉时不需要手工删文件再碰运气
  • 导入失败时能直接看到原因

7. 验收标准

本轮收口完成,必须同时满足以下条件:

7.1 协议层

  • 项目资产引用正式统一为 AssetRef
  • 不再保留旧 scene / component 项目资产路径兼容协议
  • 不再保留迁移工具

7.2 架构层

  • AssetImportService / ProjectAssetIndex / ResourceManager 的对外职责稳定
  • 运行时不再承担旧协议解释职责
  • Library 已经是正式依赖,而不是临时缓存补丁

7.3 功能层

  • OBJ / 贴图 / 材质二次打开优先命中 artifact
  • 关闭 editor 重开后项目 scene 能稳定恢复
  • builtin sphere / cube / default material 不会因为缓存系统而丢失

7.4 性能层

  • 打开含大型 OBJ 的 scene 时不长时间卡死 editor
  • 二次打开与首次导入的体感耗时有明显区分
  • 命中 artifact 后不再退回源文件同步导入主路径

7.5 工具层

  • 具备最小 Reimport / Reimport All / Clear Library 能力
  • 有最小可观测性输出

8. 本轮不做的内容

为了尽快收口,本轮明确不做以下扩展:

  • prefab 全量资产协议翻新
  • 动画 / 音频 / shader 新 importer
  • 远程缓存
  • 多项目历史版本兼容框架
  • 完整图形化导入面板
  • 一次性把所有 AssetDatabase 内部实现拆到最细

这些内容后续可以继续做,但不应该阻塞当前正式收口。


9. 推荐执行顺序

建议按下面顺序推进,避免边做边反复回滚:

  1. 先做阶段 A直接把项目协议和旧兼容删干净。
  2. 再做阶段 B把对外边界稳定下来。
  3. 然后做阶段 C把“缓存命中了但恢复仍然重”的问题收掉。
  4. 最后做阶段 D补齐最小运维与可观测性。

原因是:

  • 不先删旧兼容,后面所有逻辑都要双轨维护。
  • 不先把边界定清,性能问题会一直和历史兼容问题缠在一起。
  • 不先把主链路收稳,工具做出来也只是给过渡态续命。

10. 本轮涉及的主要代码范围

本轮预计重点落在以下文件:

  • engine/src/Components/MeshFilterComponent.cpp
  • engine/src/Components/MeshRendererComponent.cpp
  • engine/include/XCEngine/Core/Asset/ResourceManager.h
  • engine/src/Core/Asset/ResourceManager.cpp
  • engine/include/XCEngine/Core/Asset/AssetImportService.h
  • engine/src/Core/Asset/AssetImportService.cpp
  • engine/include/XCEngine/Core/Asset/ProjectAssetIndex.h
  • engine/src/Core/Asset/ProjectAssetIndex.cpp
  • engine/include/XCEngine/Core/Asset/AssetDatabase.h
  • engine/src/Core/Asset/AssetDatabase.cpp
  • editor/src/Managers/ProjectManager.cpp
  • editor/src/Commands/ProjectCommands.h
  • editor/src/Actions/EditorActions.h
  • editor/src/Actions/MainMenuActionRouter.h
  • tests/core/Asset/test_resource_manager.cpp
  • tests/Components/test_mesh_render_components.cpp
  • tests/Scene/test_scene.cpp
  • project/Assets/Scenes/Main.xc
  • project/Assets/Scenes/Backpack.xc

11. 一句话结论

从这一刻开始,这个模块的目标不再是“继续兼容旧系统”,而是:

把当前已经跑起来的 Library、artifact、AssetRef、异步恢复链路,收成一套只服务当前项目、无旧包袱、可稳定重开的正式资产系统。