Files
XCEngine/docs/api/XCEngine/Editor/Managers/ProjectManager/ProjectManager.md

7.2 KiB
Raw Blame History

ProjectManager

命名空间: XCEngine::Editor

类型: class

源文件: editor/src/Managers/ProjectManager.h

描述: IProjectManager 的默认实现,负责把项目 Assets 目录扫描成 AssetItem 树,并提供路径导航、选择同步与基础文件操作。

概述

ProjectManager 当前不是 AssetDatabase,也不是资源导入服务;但它也已经不只是“轻量文件浏览器”。

按当前实现,它承担三类稳定职责:

  • <Project>/Assets 扫描为 AssetItem 树,供 ProjectPanel 消费
  • 维护浏览路径、当前选择与刷新后的状态恢复
  • 处理创建、删除、移动、重命名等基础文件系统操作

因此它更准确的定位是:

  • editor 侧项目文件系统投影层
  • Project Browser 的默认执行层

而不是 engine 侧资产数据库本身。

内部状态模型

当前长期持有的核心状态只有四类:

状态 作用
m_rootFolder 当前 Assets 根节点。
m_path 当前浏览路径的目录节点栈,也是面包屑来源。
m_selectedItemPath 当前选中项的完整路径字符串。
m_projectPath 当前项目根目录。

这套设计的直接收益是:

  • 刷新树时,不需要保留旧 AssetItem 指针身份
  • 只要路径还能重新解析,当前目录和当前选中项就能在重建后恢复

扫描与类型推断

根目录初始化

Initialize 当前固定把 <project>/Assets 当作根目录:

  • 若目录不存在,会先创建 Assets/Assets/Scenes/
  • 根节点名称固定重写为 Assets
  • 初始化后 m_path 只包含根节点

它不会额外创建旧文档里提到的演示子目录,也不会在这里预热资产数据库。

递归扫描

ScanDirectory(...) 当前会:

  • 遍历目录项
  • 对子目录递归构建子 AssetItem
  • 跳过显示层面的 .meta 文件
  • 把目录排在文件前面,再按名称排序

这意味着 ProjectPanel 看到的是“过滤掉 .meta 侧车文件后的浏览树”,而不是磁盘上的逐项镜像。

类型推断

文件项当前主要按扩展名启发式推断:

扩展名 当前类型
图片扩展名 Texture
.fbx/.obj/.gltf/.glb Model
.cs/.cpp/.h Script
.mat Material
.xc/.unity/.scene Scene
.prefab Prefab
其他 File

同时还会记录:

  • extensionLower
  • isImageAsset
  • canUseImagePreview

ProjectPanel 的图标与缩略图策略使用。

路径导航与选择恢复

路径导航

当前路径相关公开 API 基本都围绕 m_path 工作:

  • NavigateToFolder(...)
    • 重新解析从根到目标目录的完整路径
    • 成功后清空当前选择
  • NavigateBack()
    • 只在 m_path.size() > 1 时后退
    • 后退后清空当前选择
  • NavigateToIndex(index)
    • 直接截断面包屑到指定层级
    • 同样会清空当前选择

GetCurrentPath() 始终返回从 "Assets" 开始的逻辑路径,而不是磁盘绝对路径。

选择恢复

ProjectManager 当前把选择保存成 m_selectedItemPath,而不是保留旧 AssetItemPtr

因此:

  • RefreshCurrentFolder() 重建目录树后,只要同一路径仍存在,选择可以恢复
  • 若原路径不存在,则 SyncSelection() 自动清除选择

这也是 ProjectSelectionSurvivesRefreshWhenItemOrderChanges 能成立的根本原因。

基础文件操作

当前真正值得文档化的,不是 getter / setter而是这几组带规则的写操作。

创建目录

CreateFolder 当前会:

  • trim 名称
  • 拒绝空名、... 和 Windows 非法文件名字符
  • 在当前目录下生成唯一目录名,如 New Folder 1
  • 刷新树并自动选中新目录

删除资源

DeleteItem 当前会:

  • 拒绝空路径、根目录本身和项目根之外的路径
  • 删除目标本体
  • 额外删除同名 .meta sidecar
  • 必要时清空选择
  • 刷新目录树

这里删除 .meta 并不是“顺手清理垃圾文件”,而是为了避免资源本体被移除后仍残留旧 GUID / 导入元数据。

移动资源

MoveItem 当前会:

  • 要求源和目标都位于当前 Assets 根目录之下
  • 要求目标是已存在目录
  • 禁止移动根目录本身
  • 禁止把目录移动到自己的子目录
  • 禁止覆盖已有同名目标
  • 成功后同步移动 .meta sidecar

同步移动 sidecar 的意义同样是保持资源身份与导入配置跟随资源本体一起迁移,而不是把 .meta 留在旧路径。

重命名资源

RenameItem 当前会:

  • trim 并校验新名字
  • 对文件项在“不写扩展名”时自动保留原扩展名
  • 支持 Windows 下 case-only rename
  • 成功后同步重命名 .meta sidecar
  • 若被重命名项正好是当前选中项,会同步更新 m_selectedItemPath

因此当前重命名语义已经不只是 UI 上改显示名而是显式维护资源路径、sidecar 和选择状态的一致性。

公开方法

方法 说明
Initialize 初始化项目根、确保 Assets/Scenes 存在并建立根目录树。
RefreshCurrentFolder 重建目录树并尽量保留当前路径与当前选择。
CreateFolder 在当前目录创建唯一命名的新文件夹。
DeleteItem 删除项目内资源或目录,并移除同名 .meta sidecar。
MoveItem 在项目目录内移动资源或目录,并同步移动 .meta sidecar。
RenameItem 重命名资源或目录,支持保留扩展名与 case-only rename。

其余 getter / setter / 导航方法当前语义较直接,类型页中已概述,不再逐个拆页。

测试与行为锚点

和当前 ProjectManager 直接相关的测试锚点主要在 tests/Editor/test_action_routing.cpp

  • ProjectCommandsCreateFolderMoveAssetAndOpenFolderHelper
  • ProjectCommandsCreateFolderUsesUniqueDefaultName
  • ProjectCommandsRenameAssetUpdatesSelectionAndPreservesFileExtension
  • ProjectCommandsRejectInvalidMoveTargets
  • ProjectSelectionSurvivesRefreshWhenItemOrderChanges
  • ProjectCommandsRejectMovingFolderIntoItsDescendant

这些测试虽然多数通过 ProjectCommands 外层 helper 进入,但已经把 ProjectManager 的真实文件系统行为钉得比较牢。

当前限制

  • 当前仍是主动扫描树,不是文件系统监听器模型。
  • 类型识别仍然是扩展名启发式,不直接查询资产数据库。
  • 目录扫描和大部分文件系统错误当前都以“吞异常并保持可用”为主,诊断能力较弱。
  • .meta 文件只在变更操作时被显式跟随处理,不会单独显示在浏览树里。

相关文档