# Editor Architecture And Workflow ## 先建立正确心智模型 `docs/api/XCEngine/Editor/**` 对应的是编辑器应用层,而不是引擎运行时 public API。 当前这套 Editor 已经不是“只有窗口壳和几块早期 ImGui 面板”的状态。按 `editor/src/**`、`project/` 和当前脚本程序集目录来看,它已经形成了一条真实闭环: `Application` -> `EditorContext` -> `Panels / Actions / Commands` -> `ViewportHostService` -> `Rendering / ResourceManager / ScriptEngine` 同时还和项目目录结构直接对接: - `Project.xcproject` - `Assets/` - `.meta` - `Library/SourceAssetDB` - `Library/ArtifactDB` - `Library/Artifacts` - `Library/ScriptAssemblies` 因此这组文档的重点,不是“介绍一个理想中的未来编辑器”,而是解释当前 checkout 下这条链路已经怎么工作。 ## 顶层宿主是怎样启动的 [Application](../../XCEngine/Editor/Application/Application.md) 是编辑器进程的组合根。 它的启动顺序大致是: 1. 安装崩溃过滤器并把日志重定向到可执行目录。 2. 通过 `ResolveEditorProjectRootUtf8()` 解析项目根目录。 3. 若命令行带 `--project` 或 `-p`,优先使用覆盖路径。 4. 否则在工作目录或可执行目录向上查找 workspace 根,再优先落到 `/project/`。 5. 初始化主窗口渲染器、`ResourceManager`、`EditorContext`、脚本运行时、ImGui 和 `ViewportHostService`。 6. 最后挂接 `EditorLayer`,开始每帧驱动。 这里最关键的一点是:项目根目录不是由某个面板临时决定,而是宿主层在启动时统一解析并固定下来。当前仓库默认就是随仓维护的 `project/` 示例工程。 ## 当前 Editor 的六层结构 可以把当前实现理解成六层。 ### 1. 宿主层 - `Application` - `Platform` - `D3D12WindowRenderer` - `ImGuiBackendBridge` - `ImGuiSession` 这一层负责窗口、SwapChain、ImGui 帧边界、项目切换和脚本运行时重载。它不直接实现 Hierarchy、Inspector 或 Project Browser 的业务规则。 ### 2. 上下文与共享服务层 - `EditorContext` - `EventBus` - `SelectionManager` - `SceneManager` - `ProjectManager` - `UndoManager` `EditorContext` 是当前 Editor 的状态容器。它把事件、选择、场景、项目、撤销和 `ViewportHostService` 指针聚合起来,供面板和动作层统一访问。 ### 3. 面板与布局层 - `PanelCollection` - `HierarchyPanel` - `ProjectPanel` - `InspectorPanel` - `SceneViewPanel` - `GameViewPanel` - `ConsolePanel` 这一层负责“用户看到什么”,以及把即时模式 UI 交互采样成更稳定的意图。 其中 `GameViewPanel` 还有一条额外职责:它会把视口里的键鼠状态采样成 `GameViewInputFrameEvent`,再通过 `PlaySessionController` 桥接到运行时 `InputManager`。这一条链路可以单独看: - [Game View Runtime Input Bridge](Game-View-Runtime-Input-Bridge.md) ### 4. 动作与命令层 - `Actions::*ActionRouter` - `Commands::*` 这层负责把“菜单点击、快捷键、右键菜单、拖放、行内重命名”翻译成统一的编辑语义。典型例子是: - `HierarchyActionRouter` - `EntityCommands` - `ProjectCommands` ### 5. 视口宿主层 - `ViewportHostService` - `SceneViewportOverlayProviders` - `SceneViewportOverlayBuilder` - `SceneViewportEditorOverlayPass` - `SceneViewportPicker` 它把 Scene/Game 视口真正接到引擎的 `Rendering + RHI` 上,同时承接 object-id picking、outline、grid 和世界空间 overlay。 ### 6. 引擎与资源层 - `Rendering` - `ResourceManager` - `AssetDatabase` - `ScriptEngine` - `MonoScriptRuntime` 这一层不属于 Editor 自身,但 Editor 当前已经大量依赖它们提供真实能力,而不是自己维护一套独立“简化版运行时”。 ## `EditorActionRoute` 为什么重要 很多旧文档容易忽略 [EditorActionRoute](../../XCEngine/Editor/Core/EditorActionRoute/EditorActionRoute.md),但它对当前 Inspector 和焦点行为非常关键。 当前只有三个 route: - `None` - `Hierarchy` - `Project` 这不是菜单状态,而是“最近一次明确的编辑焦点来自哪里”。 它直接影响 [InspectorPanel](../../XCEngine/Editor/panels/InspectorPanel/InspectorPanel.md) 的检查对象: - route 是 `Hierarchy` 时,优先检查当前选中实体。 - route 是 `Project` 时,优先检查当前选中资源。 - 当前只有 `Material` 资源拥有专用 inspector;其他资源走 unsupported fallback。 所以 Inspector 现在已经不是“只给 GameObject 用”的面板,而是一个带 subject 切换能力的通用检查器。 ## 一条典型的 Hierarchy 链路 以“在 Hierarchy 中重命名实体”为例,当前真实链路大致是: 1. `HierarchyPanel` 绘制树节点和行内编辑框。 2. [HierarchyActionRouter](../../XCEngine/Editor/Actions/HierarchyActionRouter/HierarchyActionRouter.md) 负责解释点击、右键、拖放和 rename 请求。 3. `RequestEntityRename(...)` 通过 [EventBus](../../XCEngine/Editor/Core/EventBus/EventBus.md) 发布 `EntityRenameRequestedEvent`。 4. 行内编辑结束后,`CommitEntityRename(...)` 调用 [EntityCommands](../../XCEngine/Editor/Commands/EntityCommands/EntityCommands.md)。 5. `EntityCommands::RenameEntity(...)` 通过 `UndoUtils::ExecuteSceneCommand(...)` 进入撤销栈。 6. `SceneManager` 完成真正的场景修改。 7. 其他面板通过选择状态或事件观察到变化。 这条链路体现了当前 editor 的一个硬边界: - 面板负责呈现和采样。 - router 负责交互语义。 - commands 负责稳定的编辑命令。 - manager 负责真正的数据结构修改。 ## 一条典型的 Project 链路 [ProjectPanel](../../XCEngine/Editor/panels/ProjectPanel/ProjectPanel.md) 不是 `AssetDatabase` 本身,而是 `IProjectManager` 的浏览器前端。 当前它的主链路是: 1. 左侧目录树用 `TreeView` 绘制 folder hierarchy。 2. 右侧浏览区用 `DrawAssetTile(...)` 绘制当前目录条目。 3. 顶部工具栏只做当前目录内搜索,不做全项目索引。 4. 面包屑通过 `NavigateToIndex(...)` 回退到任意路径段。 5. 重命名、创建文件夹、创建材质、移动资源、删除资源都交给 `ProjectCommands`。 6. 打开资源、开始拖拽、背景点击等交互交给 `Actions` 层 helper。 因此当前 `ProjectPanel` 的定位很清楚: - 它负责浏览和编辑入口。 - 它不自己维护资源数据库。 - 它依赖 project manager 和命令层维持真实状态。 还要建立一个新的工作流边界认知: - Project 面板负责资源浏览与资源级编辑 - 项目级保存和脚本程序集重建仍由主菜单触发 - 旧文档里提到的场景资源批量迁移入口已经不在当前 editor 工作流中 ## Inspector 已经不只是组件列表 [InspectorPanel](../../XCEngine/Editor/panels/InspectorPanel/InspectorPanel.md) 现在至少有四种 subject mode: - `None` - `GameObject` - `MaterialAsset` - `UnsupportedAsset` ### GameObject 模式 这一支仍然是最传统的 Inspector: - 遍历实体组件列表。 - 通过 `ComponentEditorRegistry` 找到对应 `IComponentEditor`。 - 用 `BeginComponentSection(...)` 组织 section UI。 - 组件 editor 返回 `true` 时,标记场景 dirty。 - `Add Component` 弹窗走 `DeferredPopupState` 和 `Actions` helper。 ### Material 资源模式 这一支是旧文档最容易写错的地方。当前实现已经支持直接检查材质资源: - 从 `ProjectManager` 取当前选中的 `AssetItem`。 - 仅当 `item->type == "Material"` 时进入专用 inspector。 - 通过项目相对路径调用 `ResourceManager::Load()`。 - 当前可编辑: - Shader 路径 - Shader Pass - Render Queue - Render State - Tags - 每次修改都会立刻写回材质文件,并尽量把变更同步到已加载的 `Material` 资源实例。 所以现在 Inspector 已经承担了一部分资源编辑器职责,而不是单纯的 scene component inspector。 ### ScriptComponent 不是缺席状态 旧表述里常见“Inspector 还没有脚本组件”之类的说法,但当前这已经不成立。 [ScriptComponentEditor](../../XCEngine/Editor/ComponentEditors/ScriptComponentEditor/ScriptComponentEditor.md) 已经接入当前 Inspector 链路,支持: - 脚本类选择 - 字段模型读取 - 字段 override 写回 - 运行时缺失 / 程序集缺失状态提示 - `Rebuild Scripts` / `Reload Scripts` 入口 ## 脚本程序集链路已经落地 当前脚本相关的关键目录是: - `managed/XCEngine.ScriptCore/` - `managed/GameScripts/` - `project/Assets/**/*.cs` - `project/Library/ScriptAssemblies/` [Application](../../XCEngine/Editor/Application/Application.md) 在启动、切换项目和显式 reload 时,都会把脚本程序集目录固定到: - `/Library/ScriptAssemblies/XCEngine.ScriptCore.dll` - `/Library/ScriptAssemblies/GameScripts.dll` - `/Library/ScriptAssemblies/mscorlib.dll` 若程序集缺失: - Editor 不会直接崩溃。 - `ScriptEngine` runtime 会被清空。 - `ScriptRuntimeStatus` 会保留错误消息,供 Inspector 和其他 UI 展示。 若用户触发 `RebuildScriptingAssemblies()`: 1. `EditorScriptAssemblyBuilder` 重建项目程序集。 2. 成功后立即 `ReloadScriptingRuntime()`。 3. 新 runtime 会重新注册到 `ScriptEngine`。 这条链路说明当前脚本系统已经进入“编辑器真实工作流的一部分”,而不是实验性质的旁路功能。 ## 视口链路也已经从面板里抽出来了 旧版 editor 很容易把 SceneView 相关逻辑直接堆进面板文件里,但当前实现已经明显走向规范化。 按当前结构,典型流程是: 1. `Application::Render()` 建立主帧边界。 2. `LayerStack` 和具体面板产生 Scene / Game 视口请求。 3. `ViewportHostService::BeginFrame()` 清理并准备本帧视口状态。 4. `RenderRequestedViewports(...)` 真正调用引擎 `SceneRenderer`。 5. Scene View 额外接入: - 编辑器私有相机 - object-id surface - outline - grid - `SceneViewportOverlayProviders` - `SceneViewportOverlayBuilder` - `SceneViewportEditorOverlayPass` 这意味着: - editor 是渲染宿主,不是第二套 renderer。 - 新的 Scene overlay / gizmo 功能应优先沿 `overlay provider -> overlay builder -> overlay pass` 扩展。 - 不应再把世界空间绘制逻辑继续回堆到 `SceneViewPanel` 的临时 ImGui 路径。 更细一层的 Scene View 输入仲裁、pivot / center、global / local、HUD/world overlay 分层以及 gizmo overlay state 传播关系,可继续看 [SceneView Interaction And Gizmo Model](SceneView-Interaction-And-Gizmo-Model.md)。 ## 当前项目目录结构不是“伪工作流” 当前工程目录的几个部分都已经参与真实工作流: - `project/Assets/` - `project/Assets.meta` - `project/Library/` - `project/Library/ScriptAssemblies/` - `Project.xcproject` 尤其是 `project/Library/`,在当前实现里并不只是可以无脑忽略的临时目录。它至少承接: - 资源数据库缓存 - artifact 缓存 - 脚本程序集输出 因此在 editor 文档里,不应再把 `.meta` 和 `Library/` 描述成“未来才会用到”的规划项。 ## 如果要继续扩展当前 Editor,应该从哪层下手 ### 新增一个面板 优先顺序通常是: 1. 在 `panels/` 下新建 panel。 2. 复用已有 `PanelWindowScope`、`PanelToolbarScope`、`PanelContentScope`。 3. 若面板要参与焦点切换,再接 `EditorActionRoute`。 4. 若面板会修改项目或场景,优先接命令层而不是直改 manager。 ### 给 Inspector 新增一种检查对象 优先顺序通常是: 1. 先确认新的 subject 应由哪条 route 驱动。 2. 在 `InspectorPanel::SyncSubject()` 里定义切换条件。 3. 为该资源或组件准备独立渲染函数。 4. 若涉及文件写回或场景写回,尽量复用现有 `Commands` / `ResourceManager` / `ScriptEngine`。 ### 给 Hierarchy / Project 增加新动作 优先顺序通常是: 1. 在 `Actions` 层描述入口。 2. 在 router 里解释 UI 交互。 3. 在 `Commands` 层集中写实际修改逻辑。 4. 需要后续 UI 同步时,再通过 `EventBus` 发布事件。 ## 现在不该再沿用的旧说法 以下说法已经不再适合当前活跃文档: - “Project 面板还不是完整资产导入系统” - “Inspector 还没有脚本组件” - “Editor 仍然只是轻量编辑器壳层” - “脚本程序集和项目目录结构还在规划中” 更准确的描述应当是: - 当前 Editor 仍在持续重构,但主链路已经真实落地。 - 高层结构已经能覆盖项目根目录解析、资源浏览、材质资源检查、脚本程序集重建与重载、Scene/Game 视口宿主和 object-id picking。 - 接下来的工作重点是继续把这些现有能力文档化、模块化,而不是再把它描述成只有方向没有实现的雏形。 ## 推荐阅读顺序 如果要快速建立当前 Editor 的整体认识,推荐按这个顺序读: 1. [Editor](../../XCEngine/Editor/Editor.md) 2. [Application](../../XCEngine/Editor/Application/Application.md) 3. [EventBus](../../XCEngine/Editor/Core/EventBus/EventBus.md) 4. [ProjectPanel](../../XCEngine/Editor/panels/ProjectPanel/ProjectPanel.md) 5. [InspectorPanel](../../XCEngine/Editor/panels/InspectorPanel/InspectorPanel.md) 6. [HierarchyActionRouter](../../XCEngine/Editor/Actions/HierarchyActionRouter/HierarchyActionRouter.md) 7. [EntityCommands](../../XCEngine/Editor/Commands/EntityCommands/EntityCommands.md) 8. [ViewportHostService](../../XCEngine/Editor/Viewport/ViewportHostService/ViewportHostService.md) 9. [SceneView Interaction And Gizmo Model](SceneView-Interaction-And-Gizmo-Model.md) 10. [ScriptComponentEditor](../../XCEngine/Editor/ComponentEditors/ScriptComponentEditor/ScriptComponentEditor.md) 这样读下来,基本就能把“宿主层、共享状态、面板、动作命令、视口和脚本”这几条主线拼起来。