Files
XCEngine/docs/api/XCEngine/Editor/Commands/ProjectCommands/ProjectCommands.md

8.0 KiB
Raw Blame History

ProjectCommands

命名空间: XCEngine::Editor::Commands

类型: header-helper

源文件: editor/src/Commands/ProjectCommands.h

描述: Project 工作流命令集合,封装项目切换与保存、资源浏览与文件操作,以及脚本程序集重建等高层动作。

概述

ProjectCommands 当前已经不只是“打开资源 + 建目录 + 删除/移动”的薄命令头。

ProjectCommands.h 的真实实现,它覆盖四组链路:

  • 资源浏览与编辑命令
  • 项目文档保存命令
  • 脚本程序集重建
  • 项目切换与项目目录初始化

ProjectPanel 的关系也很清楚:

  • Panel 负责 UI 与交互采样
  • Commands 负责 guard、规则和 manager / application 调用

资源命令

打开资源

CanOpenAsset(item) 当前只在两种情况下返回 true

  • item->isFolder
  • item->type == "Scene"

OpenAsset(context, item) 则进一步区分:

  • 文件夹: context.GetProjectManager().NavigateToFolder(item)
  • 场景资源: 转发到 LoadScene

因此当前“打开资源”仍然是收敛语义,不会在这里直接承载脚本、材质或图片编辑器分发。

创建文件夹

CreateFolder(projectManager, name) 当前只做最基本校验:

  • 名称不能为空

真正的唯一命名、落盘和刷新由 IProjectManager::CreateFolder 负责。

创建材质

CreateMaterial(projectManager, name) 当前会:

  1. 读取当前目录与根目录。
  2. 验证当前目录位于项目根目录内。
  3. 自动补 .mat 扩展名。
  4. 为重名文件追加数字后缀。
  5. 直接写出默认材质 JSON。
  6. RefreshCurrentFolder()
  7. 定位新建条目并设为当前选中项。

因此 ProjectPanel 右键菜单里的 Create -> Material 已经是落地命令,不再只是 UI 预留位。

删除 / 移动 / 重命名

这三类命令当前都只是把高层工作流规则收口后,再委托给 IProjectManager

  • DeleteAsset(...) -> projectManager.DeleteItem(...)
  • MoveAssetToFolder(...) -> projectManager.MoveItem(...)
  • RenameAsset(...) -> projectManager.RenameItem(...)

其中 CanMoveAssetToFolder(...) 额外承担了较完整的安全校验,包括:

  • 源与目标都必须位于项目根目录内
  • 不能移动项目根目录本身
  • 不能把目录移动到自己的子目录
  • 不能覆盖同名目标

项目保存命令

EnsureProjectStructure(projectPath)

当前会确保以下目录存在:

  • Assets/Scenes
  • .xceditor

BuildProjectDescriptor(context)

当前会结合:

  • context.GetProjectPath()
  • context.GetSceneManager().GetCurrentScenePath()

构建项目描述;当没有有效当前场景时,回退到:

  • Assets/Scenes/Main.xc

SaveProject(context)

这是当前项目保存链路的总入口,主要流程是:

  1. 检查当前 runtime mode 是否允许文档编辑。
  2. EnsureProjectStructure(context.GetProjectPath())
  3. 通过 SaveDirtySceneWithFallback(...) 保存当前场景,必要时回退到 Assets/Scenes/Main.xc
  4. context.GetProjectManager().RefreshCurrentFolder()
  5. Application::Get().SaveProjectState()
  6. SaveProjectDescriptor(context)

这说明 ProjectCommands 当前已经超出“Project 面板本地命令”的范畴,开始承担项目文档生命周期本身。

还要注意这个顺序的真实含义:

  • RefreshCurrentFolder() 只会同步 Assets 浏览树
  • SaveProjectState() 和项目描述文件会落在 Assets 之外的项目级位置

因此“保存项目”成功并不等于 ProjectPanel 一定出现明显可见变化;面板刷新更多是在保证项目资源视图和磁盘状态保持一致。

脚本程序集重建

CanRebuildScriptAssemblies(context)

当前 guard 很明确:

  • 文档编辑必须允许
  • 项目路径不能为空

RebuildScriptAssemblies(context)

这是 Scripts -> Rebuild Script Assemblies 菜单项的命令层入口。

当前流程是:

  1. 先走 CanRebuildScriptAssemblies(context)
  2. 调用 Application::RebuildScriptingAssemblies
  3. 若重建成功,执行 context.GetProjectManager().RefreshCurrentFolder()
  4. 把布尔结果直接返回给调用方。

因此它的职责边界是:

  • ProjectCommands 负责 guard 和后置刷新。
  • Application 负责真正的程序集构建。

这里有两个很实际的调用语义:

  • 返回 false 既可能是 guard 不通过,也可能是下游脚本构建失败。
  • 即使返回 trueRefreshCurrentFolder() 也不代表 ProjectPanel 一定会出现新条目,因为脚本程序集产物主要位于 <Project>/Library/ScriptAssemblies,不在 Assets 投影视图内。

项目切换与目录选择

SwitchProject(context, projectPath)

当前项目切换主流程是:

  1. 要求允许文档编辑。
  2. 要求目标路径非空。
  3. 通过 SceneEditorUtils::ConfirmSceneSwitch(context) 处理场景切换确认。
  4. EnsureProjectStructure(projectPath)
  5. Application::Get().SwitchProject(projectPath)
  6. 写回 context.SetProjectPath(projectPath)
  7. context.GetProjectManager().Initialize(projectPath)
  8. context.GetSceneManager().LoadStartupScene(projectPath)
  9. 清空选择与 undo 历史。
  10. RefreshCurrentFolder()
  11. 若成功加载启动场景,则 SaveProjectDescriptor(context)

这说明 ProjectCommands 现在也是 Project 生命周期切换的统一入口,而不是只服务 ProjectPanel

这里的重置动作也很关键:

  • ClearSelection() 保证旧项目里的资源 / 实体选择不会泄漏到新项目上下文
  • ClearHistory() 保证旧项目的撤销栈不会跨项目复用

NewProjectWithDialog(context) / OpenProjectWithDialog(context)

这两个 helper 都通过 FileDialogUtils::PickFolderDialog(...) 选择目录,然后回到 SwitchProject(...)

也就是说:

  • 对话框归它们负责
  • 真正的切换规则仍收口在 SwitchProject(...)

设计说明

当前 ProjectCommands 的设计方向很清楚:

  • 把资源管理规则集中化
  • 把项目文档保存链路集中化
  • 把项目维护类动作从菜单 / 面板层抽离出来
  • ProjectPanel 只消费命令,而不自己拼文件系统规则

当前最值得明确的一点是:旧文档里提到的项目级批量场景迁移入口已经不在这个头文件里,当前保留下来的项目维护动作只有:

  • 保存项目
  • 重建脚本程序集
  • 切换项目 / 新建项目 / 打开项目

这才是当前源码里的真实分层。

测试锚点

tests/Editor/test_action_routing.cpp 当前直接覆盖或锚定了这组命令的关键行为:

  • ProjectCommandsReportWhenScriptAssembliesCanBeRebuilt
  • ProjectCommandsCreateFolderMoveAssetAndOpenFolderHelper
  • ProjectCommandsCreateFolderUsesUniqueDefaultName
  • ProjectCommandsRenameAssetUpdatesSelectionAndPreservesFileExtension
  • ProjectCommandsRejectInvalidMoveTargets
  • ProjectCommandsRejectMovingFolderIntoItsDescendant

当前限制

  • 资源打开仍然只覆盖文件夹和场景。
  • 创建材质当前写的是内置默认 JSON 骨架,没有更复杂模板选择。
  • 删除、移动、重命名仍然没有事务预览或冲突解决 UI。
  • 资源复制 / 粘贴 / 重新导入仍未形成命令层协议。
  • 脚本重建当前只返回布尔值,不负责弹窗反馈或进度 UI主菜单层也不会消费这个返回值。

相关文档