# ScriptEngine **命名空间**: `XCEngine::Scripting` **类型**: `class (singleton)` **头文件**: `XCEngine/Scripting/ScriptEngine.h` **描述**: 当前脚本系统的总调度器,负责运行时启停、脚本实例追踪、生命周期调用、脚本类发现和字段模型拼装。 ## 概览 `ScriptEngine` 是当前脚本模块里最重要的原生协调者。它自己不执行脚本字节码,也不保存场景数据,而是负责把下面几层真正串起来: - `SceneRuntime` 提供“场景开始运行/停止运行/每帧更新”的入口。 - `ScriptComponent` 提供脚本绑定与字段缓存。 - `IScriptRuntime` 提供具体脚本后端能力。 当前它的核心职责包括: - 在运行时开始时收集场景中的脚本组件并建立追踪表。 - 订阅 `Scene::OnGameObjectCreated()`,把运行中创建的新对象也纳入脚本追踪。 - 根据对象激活状态、组件启用状态和脚本类绑定状态决定脚本是否应当运行。 - 按顺序创建实例、调用 `Awake / OnEnable / Start / Update...`。 - 在运行时字段、本地字段缓存、类元数据和类默认值之间建立一致的读取模型。 - 为编辑器/Inspector 提供脚本类列表、字段模型、批量写入和清除覆盖能力。 ## 生命周期 - [Get](Get.md) 返回进程级单例。 - 默认运行时是内部持有的 `NullScriptRuntime`。 - [SetRuntime](SetRuntime.md) 可替换具体后端;传 `nullptr` 时回退到空运行时。 - [OnRuntimeStart](OnRuntimeStart.md) / [OnRuntimeStop](OnRuntimeStop.md) 管理整条脚本运行链路。 ## 内部追踪模型 当前 `ScriptEngine` 通过 `(gameObjectUUID, scriptComponentUUID)` 唯一标识一个脚本实例状态,并保存: - `context` - `instanceCreated` - `awakeCalled` - `enabled` - `startCalled` - `startPending` 这说明当前生命周期状态是显式状态机,而不是每次调用都从托管世界反查。 ## 脚本类与字段模型 除了生命周期调度,`ScriptEngine` 还负责把运行时暴露成编辑器可消费的数据接口: - `TryGetAvailableScriptClasses()` 返回排序后的 `ScriptClassDescriptor` 列表,并可按程序集过滤。 - `TryGetScriptFieldModel()` 会把类声明字段、运行时默认值、存储覆盖值和活体托管值融合成 `ScriptFieldModel`。 - `ApplyScriptFieldWrites()` 会逐项返回 `Applied / UnknownField / TypeMismatch / StoredOnlyField` 等状态。 - `ClearScriptFieldOverrides()` 会把声明字段重置回类默认值,并删除本地存储中的覆盖项。 这也是当前 Inspector 和脚本字段编辑工具最该依赖的 API 面。 ## 线程语义 - 当前实现没有锁。 - 应视为主线程运行时服务。 - 不应该在并发线程里同时改脚本组件集合和驱动脚本生命周期。 ## 当前实现边界 - 只跟踪当前运行场景里的脚本组件。 - `Start` 生命周期会在第一次 `OnUpdate()` 前补发一次,而不是在 `OnRuntimeStart()` 里立即调用。 - `TrySetScriptFieldValue()` 只有在后端能返回类字段元数据时,才会强校验字段名和类型;否则会退回到纯本地存储写入。 - `TryGetScriptFieldModel()` 会优先使用运行时返回的类默认值,而不是简单地把每种类型置零。 - `TryGetScriptFieldSnapshots()` 在模型成功但字段为空时会返回 `false`,调用方不能把“返回 `false`”简单等同于“接口失败”。 ## 常用访问器 - `GetRuntime()` - `IsRuntimeRunning()` - `GetRuntimeScene()` 这些是简单内联访问器,当前文档重点放在影响状态机和运行行为的核心方法上。 ## 公开方法 | 方法 | 说明 | |------|------| | [Get](Get.md) | 获取全局脚本引擎实例。 | | [SetRuntime](SetRuntime.md) | 设置具体脚本后端。 | | [OnRuntimeStart](OnRuntimeStart.md) | 启动脚本运行时。 | | [OnRuntimeStop](OnRuntimeStop.md) | 停止脚本运行时。 | | [OnFixedUpdate](OnFixedUpdate.md) | 驱动固定步长脚本更新。 | | [OnUpdate](OnUpdate.md) | 驱动常规逐帧更新,并补发 `Start`。 | | [OnLateUpdate](OnLateUpdate.md) | 驱动后更新。 | | [OnScriptComponentEnabled](OnScriptComponentEnabled.md) | 处理脚本组件启用事件。 | | [OnScriptComponentDisabled](OnScriptComponentDisabled.md) | 处理脚本组件禁用事件。 | | [OnScriptComponentDestroyed](OnScriptComponentDestroyed.md) | 处理脚本组件销毁事件。 | | [OnScriptComponentClassChanged](OnScriptComponentClassChanged.md) | 处理脚本类绑定变化,销毁旧实例并按新类重建跟踪。 | | [HasTrackedScriptComponent](HasTrackedScriptComponent.md) | 查询某组件是否被跟踪。 | | [HasRuntimeInstance](HasRuntimeInstance.md) | 查询某组件是否已有运行时实例。 | | [GetTrackedScriptCount](GetTrackedScriptCount.md) | 返回当前跟踪脚本数。 | | [TryGetAvailableScriptClasses](TryGetAvailableScriptClasses.md) | 返回可绑定脚本类列表。 | | [TrySetScriptFieldValue](TrySetScriptFieldValue.md) | 写脚本字段。 | | [TryGetScriptFieldValue](TryGetScriptFieldValue.md) | 读脚本字段。 | | [ApplyScriptFieldWrites](ApplyScriptFieldWrites.md) | 批量写脚本字段并返回逐项状态。 | | [ClearScriptFieldOverrides](ClearScriptFieldOverrides.md) | 批量清理字段覆盖并恢复默认值。 | | [TryGetScriptFieldModel](TryGetScriptFieldModel.md) | 构建完整字段模型。 | | [TryGetScriptFieldSnapshots](TryGetScriptFieldSnapshots.md) | 直接返回字段快照数组。 | ## 真实行为依据 - `engine/src/Scripting/ScriptEngine.cpp` - `tests/scripting/test_script_engine.cpp` - `tests/Scene/test_scene_runtime.cpp` - `tests/scripting/test_mono_script_runtime.cpp` ## 相关文档 - [IScriptRuntime](../IScriptRuntime/IScriptRuntime.md) - [ScriptComponent](../ScriptComponent/ScriptComponent.md) - [ScriptFieldStorage](../ScriptFieldStorage/ScriptFieldStorage.md) - [Scripting Runtime And Field Model](../../../_guides/Scripting/Scripting-Runtime-And-Field-Model.md)