docs(scripting): add baseline api reference and guide

This commit is contained in:
2026-03-28 15:10:54 +08:00
parent 14c7fd69ec
commit 359fe2adb3
104 changed files with 3377 additions and 27 deletions

View File

@@ -4,47 +4,46 @@
**类型**: `module`
**描述**: 提供场景容器 `Scene` 与多场景入口 `SceneManager`,负责组织 `GameObject` 层级、场景级更新与自定义文本序列化
**描述**: 提供场景容器、多场景管理入口以及场景运行时调度器
## 概
## 概
`XCEngine/Scene` 这组头文件位于 `Scene` 目录下,但公开类型实际放在 `XCEngine::Components` 命名空间中。这反映了当前引擎的建模方式
当前 `XCEngine/Scene` 目录里的 public API 主要分成三层
- `Scene` 负责持有一组 `GameObject`
- `GameObject` 负责父子层级、`TransformComponent` 和其它组件
- `SceneManager` 负责持有多个已加载场景,并暴露“当前活动场景”入口
- [Scene](Scene/Scene.md) 负责对象树、场景级更新和场景序列化
- [SceneManager](SceneManager/SceneManager.md) 负责多场景注册与活动场景入口
- [SceneRuntime](SceneRuntime/SceneRuntime.md) 负责把某个场景真正“跑起来”,并和脚本系统衔接
这和商业引擎里常见的 Unity 风格思路接近:场景是对象集合与生命周期边界,真正可组合的行为仍然落在对象与组件层
## 当前实现成熟度
这一组 API 已经能支撑基础场景树、更新和保存/加载,但需要对当前边界保持诚实:
- `Scene::IsActive()` / `SetActive()` 当前只是存储一个标志位,不会阻止 `Update()``FixedUpdate()``LateUpdate()` 运行。
- `FindGameObjectWithTag()` 当前并没有真正的 tag 系统支持,实际按对象名称匹配。
- `Scene::~Scene()` 不会逐个调用 `DestroyGameObject()`,因此不会触发场景销毁事件,也不会为组件调用 `OnDestroy()`
- `SceneManager::LoadSceneAsync()` 当前不是异步加载,只是同步包装。
- `SceneManager` 的活动场景指针,与 `Scene` 自身的 active 标志当前是两套彼此独立的状态。
种分层和商业引擎里常见的思路接近:`Scene` 是数据与对象容器,`SceneManager` 负责更高层的场景切换,而 `SceneRuntime` 则承担运行时执行语义
## 设计要点
- `Scene` 采用“所有权集中、访问返回裸指针”的模式:内部由 `std::unique_ptr<GameObject>` 持有对象API 对外返回非拥有指针
- 根对象列表与父子层级分开维护,这让“遍历根对象”和“对象挂接到父节点”可以各自保持简单
- 序列化走的是引擎私有文本格式,而不是通用 JSON。这样实现成本低、易于直接落地组件自定义序列化但兼容性和健壮性也相对有限
- `Scene` 专注对象拥有权、查询和序列化,不直接变成庞大的运行时调度中心
- `SceneRuntime` 把脚本生命周期和场景更新顺序集中管理,避免脚本系统散落到 `Scene` 内部
- `SceneManager` 让多场景入口和单个场景数据模型解耦,便于以后扩展更复杂的场景切换策略
## 当前实现边界
- 当前公开类型都位于 `XCEngine::Components` 命名空间,而不是单独的 `XCEngine::Scene` 命名空间,这反映了引擎当前建模历史。
- `SceneRuntime` 目前只管理单个运行中的场景。
- `SceneManager::LoadSceneAsync()` 仍是同步包装,不是完整异步加载系统。
- 场景序列化使用引擎私有文本格式,强调可落地而不是通用交换格式。
## 头文件
- [Scene](Scene/Scene.md) - `Scene.h`,单个场景容器、更新入口和序列化接口。
- [SceneManager](SceneManager/SceneManager.md) - `SceneManager.h`,多场景注册表与活动场景入口。
- [Scene](Scene/Scene.md) - `Scene.h`
- [SceneManager](SceneManager/SceneManager.md) - `SceneManager.h`
- [SceneRuntime](SceneRuntime/SceneRuntime.md) - `SceneRuntime.h`
## 相关指南
- [Scene Lifecycle And Serialization](../../_guides/Scene/Scene-Lifecycle-And-Serialization.md) - 解释场景树为什么这样设计、活动状态分层意味着什么,以及当前序列化链路的实际限制。
- [Scene Lifecycle And Serialization](../../_guides/Scene/Scene-Lifecycle-And-Serialization.md) - 解释场景容器、运行时调度和序列化之间的关系,以及当前实现的真实限制。
## 相关文档
- [GameObject](../Components/GameObject/GameObject.md)
- [Component](../Components/Component/Component.md)
- [TransformComponent](../Components/TransformComponent/TransformComponent.md)
- [Scripting](../Scripting/Scripting.md)
- [上级目录](../XCEngine.md)
- [API 总索引](../../main.md)

View File

@@ -0,0 +1,33 @@
# SceneRuntime::FixedUpdate
**命名空间**: `XCEngine::Components`
**类型**: `method`
**头文件**: `XCEngine/Scene/SceneRuntime.h`
## 签名
```cpp
void FixedUpdate(float fixedDeltaTime);
```
## 作用
驱动固定步长更新阶段。
## 当前实现行为
- 只有在 `m_running == true``m_scene != nullptr``m_scene->IsActive()` 时才继续执行。
- 执行顺序固定为:
1. `ScriptEngine::Get().OnFixedUpdate(fixedDeltaTime)`
2. `m_scene->FixedUpdate(fixedDeltaTime)`
## 设计重点
脚本先于原生组件运行,这样脚本在固定步长阶段做出的状态修改能被同一帧的原生组件观察到。测试 `tests/Scene/test_scene_runtime.cpp` 已验证这个顺序。
## 相关文档
- [SceneRuntime](SceneRuntime.md)
- [SceneRuntime::Update](Update.md)

View File

@@ -0,0 +1,33 @@
# SceneRuntime::LateUpdate
**命名空间**: `XCEngine::Components`
**类型**: `method`
**头文件**: `XCEngine/Scene/SceneRuntime.h`
## 签名
```cpp
void LateUpdate(float deltaTime);
```
## 作用
驱动后更新阶段。
## 当前实现行为
-`FixedUpdate` / `Update` 一样,只有在运行中且场景活动时才执行。
- 当前顺序为:
1. `ScriptEngine::Get().OnLateUpdate(deltaTime)`
2. `m_scene->LateUpdate(deltaTime)`
## 设计含义
这维持了当前运行时一贯的脚本优先策略。对商业引擎文档来说,这一点必须明确,因为很多用户会默认认为 `LateUpdate` 主要用于相机跟随、动画后修正和最终姿态收敛,而顺序差异会直接影响结果。
## 相关文档
- [SceneRuntime](SceneRuntime.md)
- [SceneRuntime::Update](Update.md)

View File

@@ -0,0 +1,63 @@
# SceneRuntime
**命名空间**: `XCEngine::Components`
**类型**: `class`
**头文件**: `XCEngine/Scene/SceneRuntime.h`
**描述**: 把 `Scene` 的逐帧更新与 `ScriptEngine` 的运行时生命周期绑在一起的轻量执行器。
## 概览
`SceneRuntime` 不是场景数据本身,而是“让一个 `Scene` 真正跑起来”的那层对象。当前职责主要有两件:
- 管理“当前正在运行哪一个场景”。
- 在每个帧阶段先驱动脚本,再驱动原生组件更新。
这种拆分和 Unity 里“Scene 是数据容器PlayerLoop/Runtime 才是执行者”的思路接近。好处是场景对象本身可以继续承担加载、保存和对象组织职责,而运行态切换、脚本启动和帧阶段调度则集中在一个小类里。
## 生命周期
- [Start](Start.md) 会先停止旧运行时,再接管新场景。
- [Stop](Stop.md) 会通知 `ScriptEngine` 结束运行,并清空当前场景。
- 运行中 `GetScene()` 返回当前绑定场景,`IsRunning()` 表示是否处于运行状态。
## 线程语义
- 当前实现没有内部同步。
- `Start()``Stop()` 和三类帧更新函数都应视为主线程 API。
## 当前实现边界
- 只有场景本身 `IsActive()` 为真时,帧更新才会继续执行。
- 每个阶段都先调 `ScriptEngine`,再调 `Scene` 本体,因此脚本改动会在同一帧被后续原生组件看见。
- `SceneRuntime` 当前只管理单个活动场景,不负责多场景叠加或异步切换。
## 公开方法
| 方法 | 说明 |
|------|------|
| [Start](Start.md) | 开始运行一个场景。 |
| [Stop](Stop.md) | 停止当前场景运行。 |
| [FixedUpdate](FixedUpdate.md) | 驱动物理步长阶段。 |
| [Update](Update.md) | 驱动常规逐帧更新阶段。 |
| [LateUpdate](LateUpdate.md) | 驱动后更新阶段。 |
## 真实行为依据
- `engine/src/Scene/SceneRuntime.cpp`
- `tests/Scene/test_scene_runtime.cpp`
这些测试明确验证了:
- 启停会转发到 `ScriptEngine`
- 脚本生命周期调用先于原生组件。
- 非活动场景会跳过帧执行。
- 切到新场景前会先停掉旧场景。
## 相关文档
- [Scene](../Scene/Scene.md)
- [ScriptEngine](../../Scripting/ScriptEngine/ScriptEngine.md)
- [Scene Lifecycle And Serialization](../../../_guides/Scene/Scene-Lifecycle-And-Serialization.md)

View File

@@ -0,0 +1,42 @@
# SceneRuntime::Start
**命名空间**: `XCEngine::Components`
**类型**: `method`
**头文件**: `XCEngine/Scene/SceneRuntime.h`
## 签名
```cpp
void Start(Scene* scene);
```
## 作用
让一个场景进入运行状态,并启动其脚本运行时。
## 当前实现流程
`engine/src/Scene/SceneRuntime.cpp`
1. 如果当前已经在运行同一个 `scene`,直接返回。
2. 先调用 [Stop](Stop.md) 清掉旧运行时。
3. 如果传入空场景,返回。
4. 写入 `m_scene`,把 `m_running` 设为 `true`
5. 调用 `ScriptEngine::Get().OnRuntimeStart(scene)`
## 参数
| 参数 | 说明 |
|------|------|
| `scene` | 要开始运行的场景;可为空,空时表示“停掉当前运行时但不启动新场景”。 |
## 设计含义
这种“先停再启”的切换方式很直接,也和很多商业引擎的 play mode 切场景行为一致。优点是生命周期边界清晰;代价是当前没有做平滑切换或状态迁移。
## 相关文档
- [SceneRuntime](SceneRuntime.md)
- [SceneRuntime::Stop](Stop.md)

View File

@@ -0,0 +1,34 @@
# SceneRuntime::Stop
**命名空间**: `XCEngine::Components`
**类型**: `method`
**头文件**: `XCEngine/Scene/SceneRuntime.h`
## 签名
```cpp
void Stop();
```
## 作用
停止当前场景运行并结束脚本运行时。
## 当前实现行为
- 如果当前并不处于运行状态,只会把 `m_scene` 清成 `nullptr`
- 如果当前正在运行:
- 先调用 `ScriptEngine::Get().OnRuntimeStop()`
- 再把 `m_running` 置为 `false`
- 最后把 `m_scene` 清空。
## 副作用
`ScriptEngine` 当前会在 `OnRuntimeStop()` 中触发脚本的 `OnDisable``OnDestroy`、实例销毁和运行时停止回调,因此这个接口不只是“停更”,而是真正结束脚本运行态。
## 相关文档
- [SceneRuntime](SceneRuntime.md)
- [ScriptEngine::OnRuntimeStop](../../Scripting/ScriptEngine/OnRuntimeStop.md)

View File

@@ -0,0 +1,33 @@
# SceneRuntime::Update
**命名空间**: `XCEngine::Components`
**类型**: `method`
**头文件**: `XCEngine/Scene/SceneRuntime.h`
## 签名
```cpp
void Update(float deltaTime);
```
## 作用
驱动常规逐帧更新阶段。
## 当前实现行为
- 运行条件与 [FixedUpdate](FixedUpdate.md) 相同:必须正在运行,场景存在且活动。
- 当前顺序为:
1. `ScriptEngine::Get().OnUpdate(deltaTime)`
2. `m_scene->Update(deltaTime)`
## 额外说明
`ScriptEngine::OnUpdate()` 当前还负责在第一次正常帧更新前补发脚本 `Start`,因此 `SceneRuntime::Update()` 实际上承担了“脚本 Start 落地阶段”的入口职责。
## 相关文档
- [SceneRuntime](SceneRuntime.md)
- [ScriptEngine::OnUpdate](../../Scripting/ScriptEngine/OnUpdate.md)

View File

@@ -0,0 +1,28 @@
# IScriptRuntime::CreateScriptInstance
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/IScriptRuntime.h`
## 签名
```cpp
virtual bool CreateScriptInstance(
const ScriptRuntimeContext& context) = 0;
```
## 作用
为某个 `ScriptComponent` 创建对应的脚本实例。
## 契约要求
- 成功返回 `true`,失败返回 `false`
- 实现应使用 `context` 里的 UUID 和组件信息完成绑定。
## 相关文档
- [DestroyScriptInstance](DestroyScriptInstance.md)
- [ScriptEngine::OnRuntimeStart](../ScriptEngine/OnRuntimeStart.md)

View File

@@ -0,0 +1,23 @@
# IScriptRuntime::DestroyScriptInstance
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/IScriptRuntime.h`
## 签名
```cpp
virtual void DestroyScriptInstance(
const ScriptRuntimeContext& context) = 0;
```
## 作用
销毁某个脚本实例,并释放运行时后端对它的跟踪状态。
## 相关文档
- [CreateScriptInstance](CreateScriptInstance.md)
- [ScriptEngine::OnRuntimeStop](../ScriptEngine/OnRuntimeStop.md)

View File

@@ -0,0 +1,71 @@
# IScriptRuntime
**命名空间**: `XCEngine::Scripting`
**类型**: `class (abstract)`
**头文件**: `XCEngine/Scripting/IScriptRuntime.h`
**描述**: 定义引擎脚本调度层与具体脚本后端之间的统一契约。
## 概览
`IScriptRuntime``ScriptEngine` 唯一应该依赖的脚本后端接口。它把脚本后端抽象成三类能力:
- 运行时启停。
- 托管类/字段元数据查询与字段读写。
- 脚本实例创建销毁与生命周期方法调用。
这种设计让 `ScriptEngine` 能专注于“调度”,而把 Mono、GCHandle、程序集加载这些实现细节留给具体后端。
## 公开概念
### ScriptLifecycleMethod
当前生命周期枚举值为:
- `Awake`
- `OnEnable`
- `Start`
- `FixedUpdate`
- `Update`
- `LateUpdate`
- `OnDisable`
- `OnDestroy`
### ScriptRuntimeContext
`ScriptRuntimeContext` 是后端执行脚本实例时的最小上下文:
| 字段 | 说明 |
|------|------|
| `scene` | 当前运行场景。 |
| `gameObject` | 当前脚本所属对象。 |
| `component` | 当前脚本组件。 |
| `gameObjectUUID` | 原生对象 UUID。 |
| `scriptComponentUUID` | 脚本组件 UUID。 |
## 线程语义
- 接口本身不承诺线程安全。
- 当前引擎默认由主线程按固定时序调用这些方法。
## 公开方法
| 方法 | 说明 |
|------|------|
| [OnRuntimeStart](OnRuntimeStart.md) | 运行时开始时的后端入口。 |
| [OnRuntimeStop](OnRuntimeStop.md) | 运行时停止时的后端入口。 |
| [TryGetClassFieldMetadata](TryGetClassFieldMetadata.md) | 查询脚本类字段元数据。 |
| [TrySetManagedFieldValue](TrySetManagedFieldValue.md) | 向托管实例写字段。 |
| [TryGetManagedFieldValue](TryGetManagedFieldValue.md) | 从托管实例读字段。 |
| [SyncManagedFieldsToStorage](SyncManagedFieldsToStorage.md) | 把托管字段同步回本地存储。 |
| [CreateScriptInstance](CreateScriptInstance.md) | 创建脚本实例。 |
| [DestroyScriptInstance](DestroyScriptInstance.md) | 销毁脚本实例。 |
| [InvokeMethod](InvokeMethod.md) | 调用生命周期方法。 |
## 相关文档
- [ScriptEngine](../ScriptEngine/ScriptEngine.md)
- [NullScriptRuntime](../NullScriptRuntime/NullScriptRuntime.md)
- [MonoScriptRuntime](../Mono/MonoScriptRuntime/MonoScriptRuntime.md)

View File

@@ -0,0 +1,33 @@
# IScriptRuntime::InvokeMethod
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/IScriptRuntime.h`
## 签名
```cpp
virtual void InvokeMethod(
const ScriptRuntimeContext& context,
ScriptLifecycleMethod method,
float deltaTime) = 0;
```
## 作用
调用脚本实例上的某个生命周期方法。
## 参数
| 参数 | 说明 |
|------|------|
| `context` | 当前脚本实例上下文。 |
| `method` | 要调用的生命周期枚举。 |
| `deltaTime` | 帧相关时间参数;并非每个生命周期都会使用。 |
## 相关文档
- [ScriptLifecycleMethod](IScriptRuntime.md)
- [ScriptEngine::OnUpdate](../ScriptEngine/OnUpdate.md)

View File

@@ -0,0 +1,31 @@
# IScriptRuntime::OnRuntimeStart
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/IScriptRuntime.h`
## 签名
```cpp
virtual void OnRuntimeStart(Components::Scene* scene) = 0;
```
## 作用
通知具体脚本后端:某个场景的脚本运行时已经开始。
## 调用方
当前由 [ScriptEngine::OnRuntimeStart](../ScriptEngine/OnRuntimeStart.md) 调用。
## 契约要求
- 后端可以在这里做场景绑定、运行时初始化或缓存清理。
- 不应假定脚本实例已经全部创建;实例创建由后续 `CreateScriptInstance()` 驱动。
## 相关文档
- [IScriptRuntime](IScriptRuntime.md)
- [OnRuntimeStop](OnRuntimeStop.md)

View File

@@ -0,0 +1,27 @@
# IScriptRuntime::OnRuntimeStop
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/IScriptRuntime.h`
## 签名
```cpp
virtual void OnRuntimeStop(Components::Scene* scene) = 0;
```
## 作用
通知脚本后端当前场景运行时正在结束。
## 契约要求
- 应释放与当前运行场景关联的运行态资源。
- 不应再假定脚本实例继续可用。
## 相关文档
- [IScriptRuntime](IScriptRuntime.md)
- [OnRuntimeStart](OnRuntimeStart.md)

View File

@@ -0,0 +1,31 @@
# IScriptRuntime::SyncManagedFieldsToStorage
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/IScriptRuntime.h`
## 签名
```cpp
virtual void SyncManagedFieldsToStorage(
const ScriptRuntimeContext& context) = 0;
```
## 作用
把托管实例中的字段变化同步回原生侧字段存储。
## 调用时机
当前 `ScriptEngine` 会在每次生命周期方法调用后执行这一步。
## 设计意义
这让场景序列化层可以观察到运行时字段回写结果,而不要求场景系统直接理解托管对象。
## 相关文档
- [ScriptFieldStorage](../ScriptFieldStorage/ScriptFieldStorage.md)
- [InvokeMethod](InvokeMethod.md)

View File

@@ -0,0 +1,35 @@
# IScriptRuntime::TryGetClassFieldMetadata
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/IScriptRuntime.h`
## 签名
```cpp
virtual bool TryGetClassFieldMetadata(
const std::string& assemblyName,
const std::string& namespaceName,
const std::string& className,
std::vector<ScriptFieldMetadata>& outFields) const = 0;
```
## 作用
查询某个脚本类公开字段的元数据。
## 返回值语义
- 返回 `true`:后端确认这个类存在,并成功返回字段元数据。
- 返回 `false`:类不存在、后端未初始化,或后端根本不支持这类查询。
## 设计意义
`ScriptEngine` 依赖它来做字段编辑校验、字段模型拼装和运行时/本地字段差异对比。
## 相关文档
- [ScriptField](../ScriptField/ScriptField.md)
- [ScriptEngine::TryGetScriptFieldModel](../ScriptEngine/TryGetScriptFieldModel.md)

View File

@@ -0,0 +1,29 @@
# IScriptRuntime::TryGetManagedFieldValue
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/IScriptRuntime.h`
## 签名
```cpp
virtual bool TryGetManagedFieldValue(
const ScriptRuntimeContext& context,
const std::string& fieldName,
ScriptFieldValue& outValue) const = 0;
```
## 作用
从托管实例读取一个字段值。
## 当前使用方式
`ScriptEngine` 会优先尝试从运行中的托管实例读取字段;只有失败时才回退到 `ScriptFieldStorage`
## 相关文档
- [TrySetManagedFieldValue](TrySetManagedFieldValue.md)
- [ScriptEngine::TryGetScriptFieldValue](../ScriptEngine/TryGetScriptFieldValue.md)

View File

@@ -0,0 +1,30 @@
# IScriptRuntime::TrySetManagedFieldValue
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/IScriptRuntime.h`
## 签名
```cpp
virtual bool TrySetManagedFieldValue(
const ScriptRuntimeContext& context,
const std::string& fieldName,
const ScriptFieldValue& value) = 0;
```
## 作用
向一个已经存在的托管脚本实例写入字段值。
## 契约要求
- 调用时实例未必一定存在,因此实现应自行检查。
- 如果字段不存在、类型不匹配或实例不可用,应返回 `false`
## 相关文档
- [TryGetManagedFieldValue](TryGetManagedFieldValue.md)
- [ScriptEngine::TrySetScriptFieldValue](../ScriptEngine/TrySetScriptFieldValue.md)

View File

@@ -0,0 +1,45 @@
# Mono
**命名空间**: `XCEngine::Scripting`
**类型**: `submodule`
**描述**: 收纳基于 Mono 的托管脚本运行时实现。
## 概览
`docs/api/XCEngine/Scripting/Mono` 对应的是 `engine/include/XCEngine/Scripting/Mono` 子目录。它不是独立命名空间,而是脚本模块下按实现后端划分出的子目录。
当前这里的核心类型只有 [MonoScriptRuntime](MonoScriptRuntime/MonoScriptRuntime.md)。它负责:
- 初始化 Mono root domain 和 app domain。
- 加载脚本核心程序集与游戏程序集。
- 发现可用脚本类和公共实例字段。
-`ScriptComponent``GameObject` 与托管对象实例绑定起来。
- 在生命周期调用后把托管字段同步回本地存储。
## 为什么单独分目录
把 Mono 运行时放进独立子目录,而不是直接塞进 `Scripting` 根目录,有两个直接好处:
- 可以清楚区分“脚本系统公共契约”和“具体后端实现”。
- 以后如果接入别的脚本后端,这里天然就是平行扩展点。
## 当前实现边界
- 当前只实现了 Mono 后端,没有并列的 IL2CPP、Lua 或自研 VM 后端。
- 目录里只有一个 public header说明当前重点仍然是把单条托管脚本链路先跑顺。
- 内部调用注册已覆盖 `GameObject``Transform``Camera``Light``MeshFilter``MeshRenderer` 和基础日志/时间桥接,但远不是完整编辑器级 API 面。
## 头文件
- [MonoScriptRuntime](MonoScriptRuntime/MonoScriptRuntime.md) - `MonoScriptRuntime.h`
## 相关指南
- [Scripting Runtime And Field Model](../../../_guides/Scripting/Scripting-Runtime-And-Field-Model.md)
## 相关文档
- [Scripting](../Scripting.md)
- [IScriptRuntime](../IScriptRuntime/IScriptRuntime.md)

View File

@@ -0,0 +1,22 @@
# MonoScriptRuntime::Constructor
**命名空间**: `XCEngine::Scripting`
**类型**: `constructor`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
## 签名
```cpp
explicit MonoScriptRuntime(Settings settings = {});
```
## 当前实现行为
- 保存传入的 `Settings`
- 立即调用内部 `ResolveSettings()`,补全程序集目录和默认路径。
## 相关文档
- [Initialize](Initialize.md)

View File

@@ -0,0 +1,31 @@
# MonoScriptRuntime::CreateManagedComponentWrapper
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
## 签名
```cpp
MonoObject* CreateManagedComponentWrapper(
MonoClass* componentClass,
uint64_t gameObjectUUID);
```
## 当前实现行为
- 只有在运行时已初始化、`componentClass` 非空且 `gameObjectUUID` 非零时才继续。
- 查找目标托管包装类型的单参构造函数。
- 创建托管对象。
-`gameObjectUUID` 作为构造参数调用该对象构造函数。
- 如果托管构造抛异常,会记录异常并返回 `nullptr`
## 用途
当前主要服务于 internal call例如从托管脚本中获取 `Transform``Camera``Light` 等原生组件包装对象。
## 相关文档
- [TryGetFieldValue](TryGetFieldValue.md)

View File

@@ -0,0 +1,34 @@
# MonoScriptRuntime::CreateScriptInstance
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
## 签名
```cpp
bool CreateScriptInstance(
const ScriptRuntimeContext& context) override;
```
## 当前实现流程
1.`context.component` 为空,失败并记录错误。
2. 若该实例已存在,直接返回 `true`
3. 若运行时尚未初始化,先调用 [Initialize](Initialize.md)。
4. 根据组件的程序集名、命名空间和类名查找类元数据;程序集名为空时回退到 `Settings::appAssemblyName`
5. 在 app domain 中创建托管对象并执行默认构造。
6. 写入上下文字段:`gameObjectUUID``scriptComponentUUID`
7.`ScriptFieldStorage` 中能匹配上的字段写入托管对象。
8. 创建 `gcHandle` 并写入实例缓存。
## 失败路径
类不存在、分配失败、上下文字段写入失败、存储字段应用失败时都会返回 `false` 并更新 `m_lastError`
## 相关文档
- [DestroyScriptInstance](DestroyScriptInstance.md)
- [SyncManagedFieldsToStorage](SyncManagedFieldsToStorage.md)

View File

@@ -0,0 +1,24 @@
# MonoScriptRuntime::DestroyScriptInstance
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
## 签名
```cpp
void DestroyScriptInstance(
const ScriptRuntimeContext& context) override;
```
## 当前实现行为
- 通过 `(gameObjectUUID, scriptComponentUUID)` 找到实例缓存。
- 若有 `gcHandle`,先释放它。
- 再从实例缓存表删除该项。
## 相关文档
- [CreateScriptInstance](CreateScriptInstance.md)

View File

@@ -0,0 +1,21 @@
# MonoScriptRuntime::~MonoScriptRuntime
**命名空间**: `XCEngine::Scripting`
**类型**: `destructor`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
## 签名
```cpp
~MonoScriptRuntime() override;
```
## 当前实现行为
析构时直接调用 [Shutdown](Shutdown.md)。
## 相关文档
- [Shutdown](Shutdown.md)

View File

@@ -0,0 +1,22 @@
# MonoScriptRuntime::GetLastError
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
## 签名
```cpp
const std::string& GetLastError() const;
```
## 当前语义
返回最近一次初始化、类发现、实例创建或托管调用失败时记录的错误信息。
## 相关文档
- [Initialize](Initialize.md)
- [CreateScriptInstance](CreateScriptInstance.md)

View File

@@ -0,0 +1,21 @@
# MonoScriptRuntime::GetManagedInstanceCount
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
## 签名
```cpp
size_t GetManagedInstanceCount() const;
```
## 当前实现行为
直接返回实例缓存表大小。
## 相关文档
- [HasManagedInstance](HasManagedInstance.md)

View File

@@ -0,0 +1,26 @@
# MonoScriptRuntime::GetManagedInstanceObject
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
## 签名
```cpp
MonoObject* GetManagedInstanceObject(
const ScriptComponent* component) const;
```
## 当前实现行为
通过实例缓存查找并用 `mono_gchandle_get_target()` 取回托管对象指针。
## 注意事项
这是诊断和桥接接口,不是高层推荐业务 API。
## 相关文档
- [HasManagedInstance](HasManagedInstance.md)

View File

@@ -0,0 +1,25 @@
# MonoScriptRuntime::GetScriptClassNames
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
## 签名
```cpp
std::vector<std::string> GetScriptClassNames(
const std::string& assemblyName = std::string()) const;
```
## 当前实现行为
- 遍历内部类缓存。
- 若传了 `assemblyName`,只返回该程序集中的类。
- 返回值会在最后排序。
## 相关文档
- [IsClassAvailable](IsClassAvailable.md)
- [TryGetClassFieldMetadata](TryGetClassFieldMetadata.md)

View File

@@ -0,0 +1,21 @@
# MonoScriptRuntime::HasManagedInstance
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
## 签名
```cpp
bool HasManagedInstance(const ScriptComponent* component) const;
```
## 当前实现行为
查询实例缓存并检查对应 `gcHandle` 能否取回托管对象。
## 相关文档
- [GetManagedInstanceObject](GetManagedInstanceObject.md)

View File

@@ -0,0 +1,34 @@
# MonoScriptRuntime::Initialize
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
## 签名
```cpp
bool Initialize();
```
## 当前实现流程
1. 重新 `ResolveSettings()`
2. 清空 `m_lastError`
3. 若已初始化,直接返回 `true`
4. 初始化 Mono root domain。
5. 创建 app domain。
6. 加载核心程序集和游戏程序集。
7. 发现脚本类并建立缓存。
8. 成功后置 `m_initialized = true`
## 失败处理
- 若加载程序集或类发现失败,会销毁 app domain。
- 失败原因会写入 `m_lastError`
## 相关文档
- [Shutdown](Shutdown.md)
- [GetLastError](GetLastError.md)

View File

@@ -0,0 +1,34 @@
# MonoScriptRuntime::InvokeMethod
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
## 签名
```cpp
void InvokeMethod(
const ScriptRuntimeContext& context,
ScriptLifecycleMethod method,
float deltaTime) override;
```
## 当前实现行为
- 先找实例缓存和类元数据。
- 再从类元数据里取出对应生命周期方法指针。
- 若方法不存在,直接返回,不视为错误。
- 调用前暂存当前 internal call 的 `deltaTime`
- 把本次 `deltaTime` 写入 internal call 全局状态。
- 调用托管方法。
- 调用后恢复旧的 `deltaTime`
## 设计意义
这说明当前托管 `Time.deltaTime` 一类能力,并不是通过每次参数注入,而是通过 internal call 共享状态提供。
## 相关文档
- [IScriptRuntime::InvokeMethod](../../IScriptRuntime/InvokeMethod.md)

View File

@@ -0,0 +1,24 @@
# MonoScriptRuntime::IsClassAvailable
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
## 签名
```cpp
bool IsClassAvailable(
const std::string& assemblyName,
const std::string& namespaceName,
const std::string& className) const;
```
## 当前实现行为
通过内部类缓存查找 `assembly|fullName` 组合键,存在则返回 `true`
## 相关文档
- [GetScriptClassNames](GetScriptClassNames.md)

View File

@@ -0,0 +1,86 @@
# MonoScriptRuntime
**命名空间**: `XCEngine::Scripting`
**类型**: `class`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
**描述**: 基于 Mono 的脚本运行时实现负责程序集加载、类发现、实例创建、internal call 桥接和生命周期调用。
## 概览
`MonoScriptRuntime` 是当前唯一的真实托管脚本后端。它把 `ScriptEngine` 提供的抽象调用翻译成 Mono 世界里的具体动作:
- 初始化 root domain 和 app domain。
- 加载脚本核心程序集与游戏程序集。
- 发现继承 `MonoBehaviour` 的可用脚本类。
- 构建类元数据缓存。
- 创建和销毁脚本实例。
- 通过 internal call 让托管脚本访问原生 `GameObject``Transform``Camera` 等能力。
## 生命周期
- 构造时接收一份 `Settings`,并做路径补全。
- [Initialize](Initialize.md) 会完成完整 Mono 初始化流程。
- [Shutdown](Shutdown.md) 会销毁 app domain、清空类缓存与实例缓存。
- 析构会自动调用 `Shutdown()`
## 常用访问器
- `IsInitialized()`
- `GetSettings()`
- `GetLastError()`
这些访问器主要用于测试、诊断和工具层。当前文档对 `GetLastError()` 单独补页,因为它直接关系到失败排查。
## 设计要点
- `ScriptEngine` 不直接碰 Mono API所有后端细节收敛在这个类里。
- 类缓存和实例缓存都基于稳定键,便于场景重建和脚本回绑。
- internal call 注册集中在本实现里,说明当前托管 API 面是围绕 Mono 后端组织的,而不是独立脚本 ABI。
## 当前实现边界
- 当前只发现应用程序集中的非抽象 `MonoBehaviour` 子类。
- 支持的公共字段类型只覆盖 `float / double / bool / int32 / uint64 / string / Vector2 / Vector3 / Vector4 / GameObject`
- `SyncManagedFieldsToStorage()` 只会回写已经存在于 `ScriptFieldStorage` 中的字段;运行时临时字段不会自动持久化。
- `OnRuntimeStop()` 只清理当前活动场景与实例,不会做完整 `Shutdown()`
## 公开方法
| 方法 | 说明 |
|------|------|
| [Constructor](Constructor.md) | 创建 Mono 运行时对象并解析设置。 |
| [Destructor](Destructor.md) | 析构时执行 `Shutdown()`。 |
| [Initialize](Initialize.md) | 初始化 Mono 域并发现脚本类。 |
| [Shutdown](Shutdown.md) | 关闭当前 Mono 运行时。 |
| [GetLastError](GetLastError.md) | 读取最近一次错误描述。 |
| [IsClassAvailable](IsClassAvailable.md) | 查询脚本类是否已发现。 |
| [GetScriptClassNames](GetScriptClassNames.md) | 返回已发现脚本类名列表。 |
| [TryGetClassFieldMetadata](TryGetClassFieldMetadata.md) | 读取脚本类字段元数据。 |
| [HasManagedInstance](HasManagedInstance.md) | 判断某脚本组件是否已有托管实例。 |
| [GetManagedInstanceCount](GetManagedInstanceCount.md) | 返回当前托管实例数。 |
| [GetManagedInstanceObject](GetManagedInstanceObject.md) | 读取托管对象裸指针。 |
| [CreateManagedComponentWrapper](CreateManagedComponentWrapper.md) | 为原生组件创建托管包装对象。 |
| [TryGetFieldValue](TryGetFieldValue.md) | 直接读取托管实例字段。 |
| [OnRuntimeStart](OnRuntimeStart.md) | 启动脚本运行时上下文。 |
| [OnRuntimeStop](OnRuntimeStop.md) | 停止当前运行场景的托管上下文。 |
| [TrySetManagedFieldValue](TrySetManagedFieldValue.md) | 写托管字段。 |
| [TryGetManagedFieldValue](TryGetManagedFieldValue.md) | 读托管字段。 |
| [SyncManagedFieldsToStorage](SyncManagedFieldsToStorage.md) | 回写本地字段缓存。 |
| [CreateScriptInstance](CreateScriptInstance.md) | 创建脚本实例。 |
| [DestroyScriptInstance](DestroyScriptInstance.md) | 销毁脚本实例。 |
| [InvokeMethod](InvokeMethod.md) | 调用生命周期方法。 |
## 真实行为依据
- `engine/src/Scripting/Mono/MonoScriptRuntime.cpp`
- `tests/scripting/test_mono_script_runtime.cpp`
## 相关文档
- [Mono](../Mono.md)
- [IScriptRuntime](../../IScriptRuntime/IScriptRuntime.md)
- [ScriptEngine](../../ScriptEngine/ScriptEngine.md)
- [Scripting Runtime And Field Model](../../../../_guides/Scripting/Scripting-Runtime-And-Field-Model.md)

View File

@@ -0,0 +1,27 @@
# MonoScriptRuntime::OnRuntimeStart
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
## 签名
```cpp
void OnRuntimeStart(Components::Scene* scene) override;
```
## 当前实现行为
- 先把 `m_activeScene` 清空,并把 internal call 的 `deltaTime` 重置为 `0`
- 调用 [Initialize](Initialize.md)。
- 初始化成功后,把 `m_activeScene` 和 internal call 场景都指向当前 `scene`
## 设计意义
这一步的重点不是创建所有脚本实例,而是让 Mono 后端进入“可服务当前场景”的状态。
## 相关文档
- [OnRuntimeStop](OnRuntimeStop.md)

View File

@@ -0,0 +1,28 @@
# MonoScriptRuntime::OnRuntimeStop
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
## 签名
```cpp
void OnRuntimeStop(Components::Scene* scene) override;
```
## 当前实现行为
- 忽略传入场景参数。
- 清空托管实例缓存。
- 清空活动场景和 internal call 场景。
- 把 internal call 的 `deltaTime` 重置为 `0`
## 注意事项
它不会执行完整 [Shutdown](Shutdown.md),因此类缓存和 Mono 域仍然保留。
## 相关文档
- [Shutdown](Shutdown.md)

View File

@@ -0,0 +1,30 @@
# MonoScriptRuntime::Shutdown
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
## 签名
```cpp
void Shutdown();
```
## 当前实现行为
- 清空托管实例缓存。
- 清空类缓存。
- 清空所有 Mono 相关指针成员。
- 销毁 app domain。
- 重置活动场景和 internal call 上下文。
-`m_initialized` 置回 `false`
## 注意事项
`OnRuntimeStop()` 不等价于 `Shutdown()`;前者更像运行场景停止,后者则是整个 Mono 运行时关闭。
## 相关文档
- [OnRuntimeStop](OnRuntimeStop.md)

View File

@@ -0,0 +1,32 @@
# MonoScriptRuntime::SyncManagedFieldsToStorage
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
## 签名
```cpp
void SyncManagedFieldsToStorage(
const ScriptRuntimeContext& context) override;
```
## 当前实现行为
- 要求 `context.component`、实例缓存和类元数据都存在。
- 只遍历当前 `ScriptFieldStorage` 里已经存在的字段名。
- 只有字段名存在于类元数据中且类型匹配,才会从托管对象读回并写回本地缓存。
## 重要边界
这意味着:
- 托管运行时中新出现但本地没存过的字段,不会自动持久化。
- 本地字段类型如果和类定义不匹配,也不会被强行覆盖。
## 相关文档
- [CreateScriptInstance](CreateScriptInstance.md)
- [ScriptFieldStorage](../../ScriptFieldStorage/ScriptFieldStorage.md)

View File

@@ -0,0 +1,36 @@
# MonoScriptRuntime::TryGetClassFieldMetadata
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
## 签名
```cpp
bool TryGetClassFieldMetadata(
const std::string& assemblyName,
const std::string& namespaceName,
const std::string& className,
std::vector<ScriptFieldMetadata>& outFields) const override;
```
## 当前实现行为
- 先查找类缓存。
- 找不到返回 `false` 并清空输出。
- 找到后把缓存中的字段元数据复制到 `outFields`
- 最终按字段名排序。
## 字段来源边界
当前只会收录:
- 公共实例字段
- 非静态字段
- 可映射到当前支持脚本字段类型的字段
## 相关文档
- [IScriptRuntime::TryGetClassFieldMetadata](../../IScriptRuntime/TryGetClassFieldMetadata.md)

View File

@@ -0,0 +1,30 @@
# MonoScriptRuntime::TryGetFieldValue
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
## 签名
```cpp
bool TryGetFieldValue(
const ScriptComponent* component,
const std::string& fieldName,
ScriptFieldValue& outValue) const;
```
## 当前实现行为
- 先通过组件找到实例缓存。
- 再检查类元数据中是否存在该字段。
- 成功时直接从托管对象读出字段值。
## 与 `TryGetManagedFieldValue` 的区别
这个接口用 `ScriptComponent*` 作为入口,更适合测试和诊断;`TryGetManagedFieldValue()` 则是实现 `IScriptRuntime` 接口的标准路径。
## 相关文档
- [TryGetManagedFieldValue](TryGetManagedFieldValue.md)

View File

@@ -0,0 +1,28 @@
# MonoScriptRuntime::TryGetManagedFieldValue
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
## 签名
```cpp
bool TryGetManagedFieldValue(
const ScriptRuntimeContext& context,
const std::string& fieldName,
ScriptFieldValue& outValue) const override;
```
## 当前实现行为
和写路径类似:
- 先找实例缓存。
- 再找字段元数据。
- 成功后直接从托管对象字段读出当前值。
## 相关文档
- [TrySetManagedFieldValue](TrySetManagedFieldValue.md)

View File

@@ -0,0 +1,27 @@
# MonoScriptRuntime::TrySetManagedFieldValue
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/Mono/MonoScriptRuntime.h`
## 签名
```cpp
bool TrySetManagedFieldValue(
const ScriptRuntimeContext& context,
const std::string& fieldName,
const ScriptFieldValue& value) override;
```
## 当前实现行为
- 先用 `context` 找到实例缓存。
- 再在类元数据里查字段。
- 字段不存在或类型不兼容则失败。
- 成功时把原生值写进托管对象字段。
## 相关文档
- [TryGetManagedFieldValue](TryGetManagedFieldValue.md)

View File

@@ -0,0 +1,28 @@
# NullScriptRuntime::CreateScriptInstance
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/NullScriptRuntime.h`
## 签名
```cpp
bool CreateScriptInstance(const ScriptRuntimeContext& context) override;
```
## 当前实现行为
当前只做一个检查:
```cpp
return context.component != nullptr;
```
也就是说,它不创建真实实例,只是告诉上层“这个组件至少存在,可以继续走生命周期占位流程”。
## 相关文档
- [NullScriptRuntime](NullScriptRuntime.md)
- [DestroyScriptInstance](DestroyScriptInstance.md)

View File

@@ -0,0 +1,21 @@
# NullScriptRuntime::DestroyScriptInstance
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/NullScriptRuntime.h`
## 签名
```cpp
void DestroyScriptInstance(const ScriptRuntimeContext& context) override;
```
## 当前实现行为
空实现,不释放额外资源。
## 相关文档
- [NullScriptRuntime](NullScriptRuntime.md)

View File

@@ -0,0 +1,25 @@
# NullScriptRuntime::InvokeMethod
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/NullScriptRuntime.h`
## 签名
```cpp
void InvokeMethod(
const ScriptRuntimeContext& context,
ScriptLifecycleMethod method,
float deltaTime) override;
```
## 当前实现行为
空实现,不会真正调用任何脚本方法。
## 相关文档
- [NullScriptRuntime](NullScriptRuntime.md)
- [IScriptRuntime::InvokeMethod](../IScriptRuntime/InvokeMethod.md)

View File

@@ -0,0 +1,57 @@
# NullScriptRuntime
**命名空间**: `XCEngine::Scripting`
**类型**: `class`
**头文件**: `XCEngine/Scripting/NullScriptRuntime.h`
**描述**: `IScriptRuntime` 的空实现,用作无托管环境时的默认兜底后端。
## 概览
`NullScriptRuntime` 的作用不是执行脚本,而是让整个脚本系统在“没有真实脚本后端”的情况下仍然保持接口闭合:
- `ScriptEngine` 仍然可以安全持有一个运行时对象。
- 场景和脚本组件的原生数据层仍然可以工作。
- 测试或工具链不需要为“没有运行时时指针为空”额外兜底。
这是一种很典型的 Null Object 模式,在商业引擎底层模块中很常见。
## 当前实现行为
- 运行时启停是 no-op。
- 元数据查询总是失败,并清空输出数组。
- 托管写字段总是返回 `true`,相当于“我接受这个请求,但没有实际后端可写”。
- 托管读字段总是返回 `false`
- 同步字段是 no-op。
- 创建实例时,只要 `context.component` 非空就返回 `true`
- 销毁实例和生命周期调用都是 no-op。
## 设计代价
这种兜底方案能让主流程更简单,但也意味着:
- “返回成功”不一定真的代表有托管实例存在。
- 如果用户误以为自己接了真实脚本后端,问题会更偏逻辑层而不是崩溃层暴露出来。
因此文档必须清楚说明它是占位运行时,而不是简化版脚本解释器。
## 公开方法
| 方法 | 说明 |
|------|------|
| [OnRuntimeStart](OnRuntimeStart.md) | 空实现。 |
| [OnRuntimeStop](OnRuntimeStop.md) | 空实现。 |
| [TryGetClassFieldMetadata](TryGetClassFieldMetadata.md) | 始终失败并清空输出。 |
| [TrySetManagedFieldValue](TrySetManagedFieldValue.md) | 始终返回 `true`。 |
| [TryGetManagedFieldValue](TryGetManagedFieldValue.md) | 始终返回 `false`。 |
| [SyncManagedFieldsToStorage](SyncManagedFieldsToStorage.md) | 空实现。 |
| [CreateScriptInstance](CreateScriptInstance.md) | 仅检查组件指针是否存在。 |
| [DestroyScriptInstance](DestroyScriptInstance.md) | 空实现。 |
| [InvokeMethod](InvokeMethod.md) | 空实现。 |
## 相关文档
- [IScriptRuntime](../IScriptRuntime/IScriptRuntime.md)
- [ScriptEngine](../ScriptEngine/ScriptEngine.md)

View File

@@ -0,0 +1,21 @@
# NullScriptRuntime::OnRuntimeStart
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/NullScriptRuntime.h`
## 签名
```cpp
void OnRuntimeStart(Components::Scene* scene) override;
```
## 当前实现行为
空实现,只显式忽略参数,不做任何初始化。
## 相关文档
- [NullScriptRuntime](NullScriptRuntime.md)

View File

@@ -0,0 +1,21 @@
# NullScriptRuntime::OnRuntimeStop
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/NullScriptRuntime.h`
## 签名
```cpp
void OnRuntimeStop(Components::Scene* scene) override;
```
## 当前实现行为
空实现,不清理额外状态。
## 相关文档
- [NullScriptRuntime](NullScriptRuntime.md)

View File

@@ -0,0 +1,23 @@
# NullScriptRuntime::SyncManagedFieldsToStorage
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/NullScriptRuntime.h`
## 签名
```cpp
void SyncManagedFieldsToStorage(
const ScriptRuntimeContext& context) override;
```
## 当前实现行为
空实现,不做字段回写。
## 相关文档
- [NullScriptRuntime](NullScriptRuntime.md)
- [IScriptRuntime::SyncManagedFieldsToStorage](../IScriptRuntime/SyncManagedFieldsToStorage.md)

View File

@@ -0,0 +1,32 @@
# NullScriptRuntime::TryGetClassFieldMetadata
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/NullScriptRuntime.h`
## 签名
```cpp
bool TryGetClassFieldMetadata(
const std::string& assemblyName,
const std::string& namespaceName,
const std::string& className,
std::vector<ScriptFieldMetadata>& outFields) const override;
```
## 当前实现行为
- 忽略输入参数。
- 先清空 `outFields`
- 返回 `false`
## 含义
这明确表示当前不存在可查询的托管类元数据。
## 相关文档
- [NullScriptRuntime](NullScriptRuntime.md)
- [IScriptRuntime::TryGetClassFieldMetadata](../IScriptRuntime/TryGetClassFieldMetadata.md)

View File

@@ -0,0 +1,27 @@
# NullScriptRuntime::TryGetManagedFieldValue
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/NullScriptRuntime.h`
## 签名
```cpp
bool TryGetManagedFieldValue(
const ScriptRuntimeContext& context,
const std::string& fieldName,
ScriptFieldValue& outValue) const override;
```
## 当前实现行为
- 忽略所有参数。
- 不写 `outValue` 的有效结果。
- 直接返回 `false`
## 相关文档
- [NullScriptRuntime](NullScriptRuntime.md)
- [TrySetManagedFieldValue](TrySetManagedFieldValue.md)

View File

@@ -0,0 +1,30 @@
# NullScriptRuntime::TrySetManagedFieldValue
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/NullScriptRuntime.h`
## 签名
```cpp
bool TrySetManagedFieldValue(
const ScriptRuntimeContext& context,
const std::string& fieldName,
const ScriptFieldValue& value) override;
```
## 当前实现行为
- 忽略所有参数。
- 直接返回 `true`
## 注意事项
这里的成功只代表“空运行时接受了这个接口调用”,不代表真实托管实例被更新。
## 相关文档
- [NullScriptRuntime](NullScriptRuntime.md)
- [TryGetManagedFieldValue](TryGetManagedFieldValue.md)

View File

@@ -0,0 +1,27 @@
# ScriptComponent::Constructor
**命名空间**: `XCEngine::Scripting`
**类型**: `constructor`
**头文件**: `XCEngine/Scripting/ScriptComponent.h`
## 签名
```cpp
ScriptComponent();
```
## 当前实现行为
- 调用内部 `GenerateScriptComponentUUID()` 生成一个非零随机 `uint64_t`
- `m_assemblyName` 默认初始化为 `GameScripts`
- 命名空间、类名和字段存储初始为空。
## 设计意义
组件 UUID 的存在,是为了让脚本运行时实例绑定不依赖对象内存地址。这样场景序列化、反序列化和运行时重建时,脚本实例可以通过 `(GameObjectUUID, ScriptComponentUUID)` 这组键稳定识别。
## 相关文档
- [ScriptComponent](ScriptComponent.md)

View File

@@ -0,0 +1,35 @@
# ScriptComponent::Deserialize
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptComponent.h`
## 签名
```cpp
void Deserialize(std::istream& is) override;
```
## 作用
从文本流恢复脚本组件状态。
## 当前实现行为
- 先把整个流读入字符串。
-`;` 切分键值对。
- 识别 `scriptComponentUUID / assembly / namespace / class / fields`
- `fields` 会先做 `UnescapeScriptString()`,再交给 `ScriptFieldStorage::DeserializeFromString()`
## 容错行为
- 空 token 会跳过。
- 没有 `=` 的 token 会跳过。
- 未识别的键会被忽略。
## 相关文档
- [Serialize](Serialize.md)
- [ScriptFieldStorage::DeserializeFromString](../ScriptFieldStorage/DeserializeFromString.md)

View File

@@ -0,0 +1,28 @@
# ScriptComponent::GetFieldStorage
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptComponent.h`
## 签名
```cpp
ScriptFieldStorage& GetFieldStorage();
const ScriptFieldStorage& GetFieldStorage() const;
```
## 作用
访问当前脚本组件的持久化字段缓存。
## 当前语义
- 返回内部成员对象的引用,不转移所有权。
- 这份存储既用于场景序列化,也用于脚本运行时字段回写。
## 相关文档
- [ScriptFieldStorage](../ScriptFieldStorage/ScriptFieldStorage.md)
- [Serialize](Serialize.md)

View File

@@ -0,0 +1,31 @@
# ScriptComponent::GetFullClassName
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptComponent.h`
## 签名
```cpp
std::string GetFullClassName() const;
```
## 当前实现行为
- 如果 `m_className` 为空,返回空字符串。
- 如果命名空间为空,只返回类名。
- 否则返回 `namespace + "." + class`
## 用途
这个接口主要用于:
- 日志描述。
- 测试断言。
- 错误信息里构造完整脚本类名。
## 相关文档
- [ScriptComponent](ScriptComponent.md)

View File

@@ -0,0 +1,31 @@
# ScriptComponent::HasScriptClass
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptComponent.h`
## 签名
```cpp
bool HasScriptClass() const;
```
## 当前实现行为
当前只检查 `m_className` 是否为空:
```cpp
return !m_className.empty();
```
## 含义
- 这表示“是否已经绑定某个脚本类名”。
- 不代表该类在运行时中真的可用;类是否存在要看 `IScriptRuntime::TryGetClassFieldMetadata()``MonoScriptRuntime::IsClassAvailable()`
## 相关文档
- [SetScriptClass](SetScriptClass.md)
- [ScriptEngine::TryGetScriptFieldModel](../ScriptEngine/TryGetScriptFieldModel.md)

View File

@@ -0,0 +1,21 @@
# ScriptComponent::OnDestroy
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptComponent.h`
## 签名
```cpp
void OnDestroy() override;
```
## 当前实现行为
直接调用 `ScriptEngine::Get().OnScriptComponentDestroyed(this)`
## 相关文档
- [ScriptEngine::OnScriptComponentDestroyed](../ScriptEngine/OnScriptComponentDestroyed.md)

View File

@@ -0,0 +1,22 @@
# ScriptComponent::OnDisable
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptComponent.h`
## 签名
```cpp
void OnDisable() override;
```
## 当前实现行为
直接调用 `ScriptEngine::Get().OnScriptComponentDisabled(this)`
## 相关文档
- [OnEnable](OnEnable.md)
- [OnDestroy](OnDestroy.md)

View File

@@ -0,0 +1,26 @@
# ScriptComponent::OnEnable
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptComponent.h`
## 签名
```cpp
void OnEnable() override;
```
## 当前实现行为
直接转发到:
```cpp
ScriptEngine::Get().OnScriptComponentEnabled(this);
```
## 相关文档
- [OnDisable](OnDisable.md)
- [ScriptEngine::OnScriptComponentEnabled](../ScriptEngine/OnScriptComponentEnabled.md)

View File

@@ -0,0 +1,72 @@
# ScriptComponent
**命名空间**: `XCEngine::Scripting`
**类型**: `class`
**头文件**: `XCEngine/Scripting/ScriptComponent.h`
**描述**: 挂在 `GameObject` 上的脚本绑定组件,负责保存脚本类标识、组件 UUID 和字段存储。
## 概览
`ScriptComponent` 是脚本系统的数据入口。它本身不执行脚本逻辑,而是保存三类信息:
- 这个组件绑定的是哪个程序集、命名空间和类。
- 这个脚本组件自己的稳定 UUID。
- 这份脚本实例的可持久化字段缓存 `ScriptFieldStorage`
这和 Unity 场景里挂着的 `MonoBehaviour` 序列化槽位很接近,但当前实现更明确地把“数据层”和“运行时实例层”拆开了。
## 生命周期
- 构造时会生成一个非零随机 `scriptComponentUUID`
- 默认程序集名是 `GameScripts`
- 启用、禁用、销毁回调会直接转发给 `ScriptEngine`
- 序列化/反序列化会持久化 UUID、脚本类绑定和字段存储内容。
## 所有权
- `ScriptComponent` 本身归 `GameObject` 所有。
- `ScriptFieldStorage` 作为成员对象直接内嵌,不单独分配。
## 当前实现边界
- `SetScriptClass()` 只有在“之前没有脚本类,现在有了”这个转换点,才会主动通知 `ScriptEngine::OnScriptComponentEnabled()`
- 单纯修改已有脚本类名,不会自动触发一轮完整的重绑定流程。
- 反序列化使用引擎私有的分号分隔文本格式,不是通用 JSON/YAML。
## 常用访问器
- `GetAssemblyName()` / `SetAssemblyName()`
- `GetNamespaceName()` / `SetNamespaceName()`
- `GetClassName()` / `SetClassName()`
- `GetScriptComponentUUID()`
这些访问器大多是简单内联函数,因此当前文档重点放在会改变生命周期或序列化语义的核心方法上。
## 公开方法
| 方法 | 说明 |
|------|------|
| [Constructor](Constructor.md) | 创建组件并生成 UUID。 |
| [SetScriptClass](SetScriptClass.md) | 设置脚本类绑定。 |
| [HasScriptClass](HasScriptClass.md) | 判断当前是否已经绑定脚本类。 |
| [GetFullClassName](GetFullClassName.md) | 返回带命名空间的完整类名。 |
| [GetFieldStorage](GetFieldStorage.md) | 访问持久化字段缓存。 |
| [OnEnable](OnEnable.md) | 通知 `ScriptEngine` 组件启用。 |
| [OnDisable](OnDisable.md) | 通知 `ScriptEngine` 组件禁用。 |
| [OnDestroy](OnDestroy.md) | 通知 `ScriptEngine` 组件销毁。 |
| [Serialize](Serialize.md) | 把组件状态写出到文本流。 |
| [Deserialize](Deserialize.md) | 从文本流恢复组件状态。 |
## 真实行为依据
- `engine/src/Scripting/ScriptComponent.cpp`
- `tests/scripting/test_script_component.cpp`
## 相关文档
- [ScriptEngine](../ScriptEngine/ScriptEngine.md)
- [ScriptFieldStorage](../ScriptFieldStorage/ScriptFieldStorage.md)
- [Scripting Runtime And Field Model](../../../_guides/Scripting/Scripting-Runtime-And-Field-Model.md)

View File

@@ -0,0 +1,39 @@
# ScriptComponent::Serialize
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptComponent.h`
## 签名
```cpp
void Serialize(std::ostream& os) const override;
```
## 作用
把脚本组件的原生数据状态写到文本流。
## 当前实现行为
当前会按键值对形式写出:
- `scriptComponentUUID`
- `assembly`
- `namespace`
- `class`
- `fields`
字符串内容会经过 `EscapeScriptString()` 转义,字段存储则通过 `ScriptFieldStorage::SerializeToString()` 序列化后再整体转义。
## 注意事项
- 这是引擎私有格式,不承诺对外通用。
- `fields` 本身是嵌套序列化文本,因此二次转义是必须的。
## 相关文档
- [Deserialize](Deserialize.md)
- [ScriptField::EscapeScriptString](../ScriptField/EscapeScriptString.md)

View File

@@ -0,0 +1,39 @@
# ScriptComponent::SetScriptClass
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptComponent.h`
## 签名
```cpp
void SetScriptClass(
const std::string& namespaceName,
const std::string& className);
void SetScriptClass(
const std::string& assemblyName,
const std::string& namespaceName,
const std::string& className);
```
## 作用
设置当前脚本组件绑定的托管类信息。
## 当前实现行为
- 两个重载都会先记录“之前是否已经有脚本类”。
- 然后覆盖程序集名、命名空间和类名。
- 只有在“之前没有脚本类,设置后有脚本类”时,才会主动调用 `ScriptEngine::Get().OnScriptComponentEnabled(this)`
## 设计含义
当前实现把“首次绑定脚本类”视作一个启用事件,但并没有把“换到另一个脚本类”也当成完整重建流程。这是一个当前版本的真实边界,用户不应该误以为修改类名会自动完成热切换。
## 相关文档
- [HasScriptClass](HasScriptClass.md)
- [OnEnable](OnEnable.md)

View File

@@ -0,0 +1,25 @@
# ScriptEngine::Get
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptEngine.h`
## 签名
```cpp
static ScriptEngine& Get();
```
## 当前实现行为
返回函数内静态单例。
## 设计意义
当前脚本系统被组织成全局运行时服务,这样 `SceneRuntime``ScriptComponent` 和工具代码都能通过统一入口触达同一套状态。
## 相关文档
- [ScriptEngine](ScriptEngine.md)

View File

@@ -0,0 +1,21 @@
# ScriptEngine::GetTrackedScriptCount
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptEngine.h`
## 签名
```cpp
size_t GetTrackedScriptCount() const;
```
## 当前实现行为
内联返回 `m_scriptOrder.size()`,即当前被调度层纳入跟踪的脚本组件数。
## 相关文档
- [HasTrackedScriptComponent](HasTrackedScriptComponent.md)

View File

@@ -0,0 +1,25 @@
# ScriptEngine::HasRuntimeInstance
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptEngine.h`
## 签名
```cpp
bool HasRuntimeInstance(const ScriptComponent* component) const;
```
## 当前实现行为
只有对应状态存在且 `instanceCreated == true` 时返回 `true`
## 注意事项
这反映的是原生调度层状态,而不是直接去后端查询对象句柄。
## 相关文档
- [HasTrackedScriptComponent](HasTrackedScriptComponent.md)

View File

@@ -0,0 +1,21 @@
# ScriptEngine::HasTrackedScriptComponent
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptEngine.h`
## 签名
```cpp
bool HasTrackedScriptComponent(const ScriptComponent* component) const;
```
## 当前实现行为
通过内部状态表查找该组件是否已被 `ScriptEngine` 追踪。
## 相关文档
- [HasRuntimeInstance](HasRuntimeInstance.md)

View File

@@ -0,0 +1,31 @@
# ScriptEngine::OnFixedUpdate
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptEngine.h`
## 签名
```cpp
void OnFixedUpdate(float fixedDeltaTime);
```
## 当前实现行为
- 只在 `m_runtimeRunning` 为真时继续执行。
- 复制当前脚本顺序表,按顺序遍历。
- 对每个脚本要求同时满足:
- `ShouldScriptRun(state)`
- `EnsureScriptReady(state, true)`
- `state.enabled == true`
- 满足后调用运行时 `FixedUpdate` 生命周期。
## 设计意义
复制顺序表再遍历,可以避免遍历过程中容器被增删时直接打乱当前帧顺序。
## 相关文档
- [OnUpdate](OnUpdate.md)

View File

@@ -0,0 +1,21 @@
# ScriptEngine::OnLateUpdate
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptEngine.h`
## 签名
```cpp
void OnLateUpdate(float deltaTime);
```
## 当前实现行为
`OnFixedUpdate()` 类似,只是在最终阶段调用 `LateUpdate(deltaTime)` 生命周期。
## 相关文档
- [OnUpdate](OnUpdate.md)

View File

@@ -0,0 +1,35 @@
# ScriptEngine::OnRuntimeStart
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptEngine.h`
## 签名
```cpp
void OnRuntimeStart(Components::Scene* scene);
```
## 当前实现流程
`engine/src/Scripting/ScriptEngine.cpp`
1. 先调用 `OnRuntimeStop()` 清理旧运行时。
2. 如果 `scene == nullptr`,直接返回。
3. 记录 `m_runtimeScene`,置 `m_runtimeRunning = true`
4. 调用当前运行时 `m_runtime->OnRuntimeStart(scene)`
5. 订阅 `scene->OnGameObjectCreated()`,保证运行中创建的新对象也会被脚本系统追踪。
6. 递归收集场景现有的所有 `ScriptComponent`
7. 对满足 `ShouldScriptRun()` 的组件调用 `EnsureScriptReady(..., true)`,从而创建实例并触发 `Awake / OnEnable`
## 设计重点
- 这一步不会直接触发 `Start``Start` 留到第一次 `OnUpdate()` 再补发。
- 订阅场景创建事件,保证 runtime-spawn 出来的对象不会漏掉脚本初始化。
## 相关文档
- [OnRuntimeStop](OnRuntimeStop.md)
- [OnUpdate](OnUpdate.md)

View File

@@ -0,0 +1,36 @@
# ScriptEngine::OnRuntimeStop
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptEngine.h`
## 签名
```cpp
void OnRuntimeStop();
```
## 当前实现流程
- 如果订阅了场景创建事件,会先退订并处理退订队列。
- 若当前并未运行:
- 清空 `m_runtimeScene`
- 清空跟踪状态和顺序表
- 返回
- 若正在运行:
- 遍历所有跟踪脚本,调用 `StopTrackingScript(..., true)`
- 清空状态表与顺序表
-`m_runtimeRunning` 置为 `false`
- 清空 `m_runtimeScene`
- 最后调用 `m_runtime->OnRuntimeStop(stoppedScene)`
## 当前真实语义
`StopTrackingScript()` 会在实例存在时按 `OnDisable -> OnDestroy -> DestroyScriptInstance` 清理,因此这不是简单停更,而是完整结束脚本运行态。
## 相关文档
- [OnRuntimeStart](OnRuntimeStart.md)
- [OnScriptComponentDestroyed](OnScriptComponentDestroyed.md)

View File

@@ -0,0 +1,23 @@
# ScriptEngine::OnScriptComponentDestroyed
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptEngine.h`
## 签名
```cpp
void OnScriptComponentDestroyed(ScriptComponent* component);
```
## 当前实现行为
- 只有运行时启动且组件存在时处理。
- 找到对应状态后调用 `StopTrackingScript(..., false)`
- 这会在需要时触发 `OnDisable``OnDestroy`、实例销毁,并把该组件从跟踪表移除。
## 相关文档
- [HasTrackedScriptComponent](HasTrackedScriptComponent.md)

View File

@@ -0,0 +1,24 @@
# ScriptEngine::OnScriptComponentDisabled
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptEngine.h`
## 签名
```cpp
void OnScriptComponentDisabled(ScriptComponent* component);
```
## 当前实现行为
- 只有运行时已启动、组件存在且当前状态 `enabled == true` 时才继续。
- 调用 `OnDisable` 生命周期。
- 然后把 `state.enabled` 置为 `false`
## 相关文档
- [OnScriptComponentEnabled](OnScriptComponentEnabled.md)
- [OnScriptComponentDestroyed](OnScriptComponentDestroyed.md)

View File

@@ -0,0 +1,24 @@
# ScriptEngine::OnScriptComponentEnabled
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptEngine.h`
## 签名
```cpp
void OnScriptComponentEnabled(ScriptComponent* component);
```
## 当前实现行为
- 只有运行时已启动且 `component` 非空时才处理。
- 会先把组件纳入跟踪表。
- 如果当前满足 `ShouldScriptRun()`,则立刻尝试 `EnsureScriptReady(..., true)`,从而补齐实例创建、`Awake``OnEnable`
## 相关文档
- [OnScriptComponentDisabled](OnScriptComponentDisabled.md)
- [ScriptComponent::OnEnable](../ScriptComponent/OnEnable.md)

View File

@@ -0,0 +1,29 @@
# ScriptEngine::OnUpdate
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptEngine.h`
## 签名
```cpp
void OnUpdate(float deltaTime);
```
## 当前实现行为
`OnFixedUpdate()` 类似,但多了一步关键逻辑:
- 如果 `state.startPending && !state.startCalled`,先调用一次 `Start`
- 随后再调用 `Update(deltaTime)`
## 为什么 `Start` 在这里触发
当前实现选择把 `Start` 定义成“第一次正常逐帧更新前的初始化阶段”,而不是运行时刚启动就立刻调用。这和很多商业引擎的语义更接近,也更利于保证对象与脚本都已经进入稳定运行态。
## 相关文档
- [OnRuntimeStart](OnRuntimeStart.md)
- [OnLateUpdate](OnLateUpdate.md)

View File

@@ -0,0 +1,100 @@
# ScriptEngine
**命名空间**: `XCEngine::Scripting`
**类型**: `class (singleton)`
**头文件**: `XCEngine/Scripting/ScriptEngine.h`
**描述**: 当前脚本系统的总调度器,负责运行时启停、脚本实例追踪、生命周期调用与字段模型拼装。
## 概览
`ScriptEngine` 是当前脚本模块里最重要的原生协调者。它自己不执行脚本字节码,也不保存场景数据,而是负责把下面几层真正串起来:
- `SceneRuntime` 提供“场景开始运行/停止运行/每帧更新”的入口。
- `ScriptComponent` 提供脚本绑定与字段缓存。
- `IScriptRuntime` 提供具体脚本后端能力。
当前它的核心职责包括:
- 在运行时开始时收集场景中的脚本组件并建立追踪表。
- 根据对象激活状态、组件启用状态和脚本类绑定状态决定脚本是否应当运行。
- 按顺序创建实例、调用 `Awake / OnEnable / Start / Update...`
- 在运行时字段、本地字段缓存和类元数据之间建立一致的读取模型。
## 生命周期
- [Get](Get.md) 返回进程级单例。
- 默认运行时是内部持有的 `NullScriptRuntime`
- [SetRuntime](SetRuntime.md) 可替换具体后端;传 `nullptr` 时回退到空运行时。
- [OnRuntimeStart](OnRuntimeStart.md) / [OnRuntimeStop](OnRuntimeStop.md) 管理整条脚本运行链路。
## 内部追踪模型
当前 `ScriptEngine` 通过 `(gameObjectUUID, scriptComponentUUID)` 唯一标识一个脚本实例状态,并保存:
- `context`
- `instanceCreated`
- `awakeCalled`
- `enabled`
- `startCalled`
- `startPending`
这说明当前生命周期状态是显式状态机,而不是每次调用都从托管世界反查。
## 线程语义
- 当前实现没有锁。
- 应视为主线程运行时服务。
- 不应该在并发线程里同时改脚本组件集合和驱动脚本生命周期。
## 当前实现边界
- 只跟踪当前运行场景里的脚本组件。
- `Start` 生命周期会在第一次 `OnUpdate()` 前补发一次,而不是在 `OnRuntimeStart()` 里立即调用。
- `TrySetScriptFieldValue()` 只有在后端能返回类字段元数据时,才会强校验字段名和类型。
- `TryGetScriptFieldModel()` 会把类元数据、运行时值和本地存储值融合成一份快照模型,这对调试和编辑器非常重要。
## 常用访问器
- `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) | 处理脚本组件销毁事件。 |
| [HasTrackedScriptComponent](HasTrackedScriptComponent.md) | 查询某组件是否被跟踪。 |
| [HasRuntimeInstance](HasRuntimeInstance.md) | 查询某组件是否已有运行时实例。 |
| [GetTrackedScriptCount](GetTrackedScriptCount.md) | 返回当前跟踪脚本数。 |
| [TrySetScriptFieldValue](TrySetScriptFieldValue.md) | 写脚本字段。 |
| [TryGetScriptFieldValue](TryGetScriptFieldValue.md) | 读脚本字段。 |
| [TryGetScriptFieldModel](TryGetScriptFieldModel.md) | 构建完整字段模型。 |
| [TryGetScriptFieldSnapshots](TryGetScriptFieldSnapshots.md) | 直接返回字段快照数组。 |
## 真实行为依据
- `engine/src/Scripting/ScriptEngine.cpp`
- `tests/scripting/test_script_engine.cpp`
- `tests/Scene/test_scene_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)

View File

@@ -0,0 +1,28 @@
# ScriptEngine::SetRuntime
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptEngine.h`
## 签名
```cpp
void SetRuntime(IScriptRuntime* runtime);
```
## 当前实现行为
- 传入非空指针时,直接把 `m_runtime` 指向该对象。
- 传入 `nullptr` 时,回退到内部持有的 `m_nullRuntime`
## 注意事项
- 不转移所有权;调用方需要自己保证外部运行时对象的生命周期。
- 当前没有在切换时自动停掉已有运行时,实际使用时应先处理好时序。
## 相关文档
- [IScriptRuntime](../IScriptRuntime/IScriptRuntime.md)
- [NullScriptRuntime](../NullScriptRuntime/NullScriptRuntime.md)

View File

@@ -0,0 +1,61 @@
# ScriptEngine::TryGetScriptFieldModel
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptEngine.h`
## 签名
```cpp
bool TryGetScriptFieldModel(
const ScriptComponent* component,
ScriptFieldModel& outModel) const;
```
## 作用
构建一份融合类元数据、托管值和本地缓存值的完整字段模型。
## 当前实现逻辑
### 1. 判定类状态
- 没绑定脚本类:`Unassigned`
- 绑定了脚本类且后端能返回元数据:`Available`
- 绑定了脚本类但后端查不到:`Missing`
### 2. 为已声明字段建立快照
对于运行时可见的每个字段:
- 先用字段类型生成默认值。
- 如果本地存储里有同名字段,则记录 `storedType / storedValue`
- 若类型不匹配,标记 `TypeMismatch`
- 若托管实例可读该字段,则当前值来源记为 `ManagedValue`
- 否则若本地存储类型匹配,则当前值来源记为 `StoredValue`
### 3. 追加仅存储字段
如果本地缓存里有字段名,但类元数据里没有:
- 会以 `StoredOnly` 问题状态附加到模型末尾。
### 4. 排序规则
- 当类状态不是 `Available` 时,会按字段名整体排序。
- 类状态为 `Available` 时,已声明字段按运行时元数据顺序构建,存储遗留字段再追加。
## 为什么这很重要
这套模型不是“为了文档好看”,而是当前脚本系统里最接近商业引擎 Inspector 数据模型的一层。它让工具或调试界面能回答这些关键问题:
- 这个字段类里声明了吗?
- 当前显示的是托管值还是存储值?
- 本地存储是否已经和类定义不匹配?
## 相关文档
- [TryGetScriptFieldSnapshots](TryGetScriptFieldSnapshots.md)
- [ScriptField](../ScriptField/ScriptField.md)

View File

@@ -0,0 +1,25 @@
# ScriptEngine::TryGetScriptFieldSnapshots
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptEngine.h`
## 签名
```cpp
bool TryGetScriptFieldSnapshots(
const ScriptComponent* component,
std::vector<ScriptFieldSnapshot>& outFields) const;
```
## 当前实现行为
- 内部直接调用 [TryGetScriptFieldModel](TryGetScriptFieldModel.md)。
- 成功后把 `model.fields` 移交给 `outFields`
- 如果结果为空,返回 `false`
## 相关文档
- [TryGetScriptFieldModel](TryGetScriptFieldModel.md)

View File

@@ -0,0 +1,31 @@
# ScriptEngine::TryGetScriptFieldValue
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptEngine.h`
## 签名
```cpp
bool TryGetScriptFieldValue(
const ScriptComponent* component,
const std::string& fieldName,
ScriptFieldValue& outValue) const;
```
## 当前实现行为
- 先检查参数。
- 如果运行时正在运行且该组件已有实例,会优先向运行时请求托管字段值。
- 只有运行时读取失败时,才回退到 `ScriptFieldStorage`
## 含义
这让用户看到的字段值尽量反映“当前活实例真实状态”,而不只是场景文件里最后一次保存的值。
## 相关文档
- [TrySetScriptFieldValue](TrySetScriptFieldValue.md)
- [TryGetScriptFieldModel](TryGetScriptFieldModel.md)

View File

@@ -0,0 +1,40 @@
# ScriptEngine::TrySetScriptFieldValue
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptEngine.h`
## 签名
```cpp
bool TrySetScriptFieldValue(
ScriptComponent* component,
const std::string& fieldName,
ScriptFieldType type,
const ScriptFieldValue& value);
```
## 当前实现流程
1. 先拒绝空组件、空字段名或类型/值不兼容的请求。
2. 如果组件已绑定脚本类,并且运行时能返回类字段元数据:
- 字段必须存在。
- 字段类型必须完全匹配。
3. 如果当前运行时正在运行,且组件已有实例:
- 先尝试写托管字段。
- 托管写失败则整体失败。
4. 托管写通过后,再写入 `ScriptFieldStorage`
## 设计意义
当前实现坚持“先过元数据校验,再写活实例,最后更新本地缓存”这条顺序。这样可以避免:
- 向不存在的托管字段写脏数据。
- 运行时值与本地缓存不一致。
## 相关文档
- [TryGetScriptFieldValue](TryGetScriptFieldValue.md)
- [TryGetScriptFieldModel](TryGetScriptFieldModel.md)

View File

@@ -0,0 +1,27 @@
# CreateDefaultScriptFieldValue
**命名空间**: `XCEngine::Scripting`
**类型**: `function`
**头文件**: `XCEngine/Scripting/ScriptField.h`
## 签名
```cpp
ScriptFieldValue CreateDefaultScriptFieldValue(ScriptFieldType type);
```
## 当前实现行为
为每种支持类型返回一个显式默认值,例如:
- 数值类型返回 `0`
- `Bool` 返回 `false`
- `String` 返回空字符串
- 向量返回 `Zero()`
- `GameObject` 返回 UUID 为 `0` 的引用
## 相关文档
- [IsScriptFieldValueCompatible](IsScriptFieldValueCompatible.md)

View File

@@ -0,0 +1,25 @@
# EscapeScriptString
**命名空间**: `XCEngine::Scripting`
**类型**: `function`
**头文件**: `XCEngine/Scripting/ScriptField.h`
## 签名
```cpp
std::string EscapeScriptString(const std::string& value);
```
## 当前实现行为
对非安全字符做 `%XX` 百分号编码。当前视为安全的字符包括字母数字、`_ - . /` 和空格。
## 用途
用于脚本组件和字段存储的私有文本序列化格式,避免 `= ; |` 等分隔符破坏解析。
## 相关文档
- [UnescapeScriptString](UnescapeScriptString.md)

View File

@@ -0,0 +1,27 @@
# IsScriptFieldValueCompatible
**命名空间**: `XCEngine::Scripting`
**类型**: `function`
**头文件**: `XCEngine/Scripting/ScriptField.h`
## 签名
```cpp
bool IsScriptFieldValueCompatible(
ScriptFieldType type,
const ScriptFieldValue& value);
```
## 当前实现行为
`std::variant` 当前持有的替代类型逐项匹配,不做自动转换。
## 含义
`Int32``UInt64``float``double` 等都被视为不同类型,必须显式匹配。
## 相关文档
- [CreateDefaultScriptFieldValue](CreateDefaultScriptFieldValue.md)

View File

@@ -0,0 +1,75 @@
# ScriptField
**命名空间**: `XCEngine::Scripting`
**类型**: `utility header`
**头文件**: `XCEngine/Scripting/ScriptField.h`
**描述**: 定义脚本字段类型系统、字段快照模型以及序列化/反序列化辅助函数。
## 概览
`ScriptField.h` 是当前脚本字段系统的核心协议头。它既定义“允许持久化哪些字段类型”,也定义“如何把字段值在文本、原生缓存和托管运行时之间搬运”。
## 公开类型
### ScriptFieldType
当前支持:
- `None`
- `Float`
- `Double`
- `Bool`
- `Int32`
- `UInt64`
- `String`
- `Vector2`
- `Vector3`
- `Vector4`
- `GameObject`
### ScriptFieldValue
当前是一个 `std::variant`,可持有:
- `std::monostate`
- `float`
- `double`
- `bool`
- `int32_t`
- `uint64_t`
- `std::string`
- `Math::Vector2`
- `Math::Vector3`
- `Math::Vector4`
- `GameObjectReference`
### ScriptFieldSnapshot / ScriptFieldModel
它们用于字段面板、字段模型比对和“已声明字段 vs 已存储字段”诊断。`ScriptEngine::TryGetScriptFieldModel()` 会用到这组结构。
## 设计要点
- 字段类型集合是显式白名单,而不是任意模板反射。
- 文本序列化逻辑集中在这个头对应的实现里,保证 `ScriptFieldStorage` 和脚本组件共用同一套规则。
- `StoredOnly``TypeMismatch` 这类问题状态被直接编码进快照模型,便于编辑器或调试工具解释当前字段状态。
## 公开函数
| 函数 | 说明 |
|------|------|
| [ScriptFieldTypeToString](ScriptFieldTypeToString.md) | 枚举转字符串。 |
| [TryParseScriptFieldType](TryParseScriptFieldType.md) | 字符串转枚举。 |
| [IsScriptFieldValueCompatible](IsScriptFieldValueCompatible.md) | 判断类型和值是否兼容。 |
| [CreateDefaultScriptFieldValue](CreateDefaultScriptFieldValue.md) | 创建某个类型的默认值。 |
| [SerializeScriptFieldValue](SerializeScriptFieldValue.md) | 把字段值序列化成文本。 |
| [TryDeserializeScriptFieldValue](TryDeserializeScriptFieldValue.md) | 从文本恢复字段值。 |
| [EscapeScriptString](EscapeScriptString.md) | 转义脚本文本字符串。 |
| [UnescapeScriptString](UnescapeScriptString.md) | 反转义脚本文本字符串。 |
## 相关文档
- [ScriptFieldStorage](../ScriptFieldStorage/ScriptFieldStorage.md)
- [ScriptEngine](../ScriptEngine/ScriptEngine.md)

View File

@@ -0,0 +1,21 @@
# ScriptFieldTypeToString
**命名空间**: `XCEngine::Scripting`
**类型**: `function`
**头文件**: `XCEngine/Scripting/ScriptField.h`
## 签名
```cpp
std::string ScriptFieldTypeToString(ScriptFieldType type);
```
## 当前实现行为
`ScriptFieldType` 枚举映射为稳定字符串,如 `Float``Vector3``GameObject`。未知值默认回退到 `None`
## 相关文档
- [TryParseScriptFieldType](TryParseScriptFieldType.md)

View File

@@ -0,0 +1,28 @@
# SerializeScriptFieldValue
**命名空间**: `XCEngine::Scripting`
**类型**: `function`
**头文件**: `XCEngine/Scripting/ScriptField.h`
## 签名
```cpp
std::string SerializeScriptFieldValue(
ScriptFieldType type,
const ScriptFieldValue& value);
```
## 当前实现行为
- 先检查类型和值兼容。
- 标量类型直接转文本。
- `Bool` 序列化为 `1``0`
- 字符串先经过 `EscapeScriptString()`
- 向量序列化为逗号分隔文本。
- `GameObject` 序列化为 UUID 数字文本。
## 相关文档
- [TryDeserializeScriptFieldValue](TryDeserializeScriptFieldValue.md)

View File

@@ -0,0 +1,28 @@
# TryDeserializeScriptFieldValue
**命名空间**: `XCEngine::Scripting`
**类型**: `function`
**头文件**: `XCEngine/Scripting/ScriptField.h`
## 签名
```cpp
bool TryDeserializeScriptFieldValue(
ScriptFieldType type,
const std::string& value,
ScriptFieldValue& outValue);
```
## 当前实现行为
- 数值类型通过标准库解析。
- `Bool` 接受 `"1"``"true"``"True"` 作为真。
- 向量支持逗号或空格分隔。
- 字符串会先做 `UnescapeScriptString()`
- 解析异常统一返回 `false`
## 相关文档
- [SerializeScriptFieldValue](SerializeScriptFieldValue.md)

View File

@@ -0,0 +1,23 @@
# TryParseScriptFieldType
**命名空间**: `XCEngine::Scripting`
**类型**: `function`
**头文件**: `XCEngine/Scripting/ScriptField.h`
## 签名
```cpp
bool TryParseScriptFieldType(
const std::string& value,
ScriptFieldType& outType);
```
## 当前实现行为
只接受当前实现里硬编码支持的类型名;匹配失败返回 `false`
## 相关文档
- [ScriptFieldTypeToString](ScriptFieldTypeToString.md)

View File

@@ -0,0 +1,21 @@
# UnescapeScriptString
**命名空间**: `XCEngine::Scripting`
**类型**: `function`
**头文件**: `XCEngine/Scripting/ScriptField.h`
## 签名
```cpp
std::string UnescapeScriptString(const std::string& value);
```
## 当前实现行为
`%XX` 形式的十六进制编码恢复成原字符;不合法的转义序列会按原样保留。
## 相关文档
- [EscapeScriptString](EscapeScriptString.md)

View File

@@ -0,0 +1,21 @@
# ScriptFieldStorage::Clear
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptFieldStorage.h`
## 签名
```cpp
void Clear();
```
## 当前实现行为
直接清空内部字段表。
## 相关文档
- [Remove](Remove.md)

View File

@@ -0,0 +1,21 @@
# ScriptFieldStorage::Contains
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptFieldStorage.h`
## 签名
```cpp
bool Contains(const std::string& fieldName) const;
```
## 当前实现行为
检查内部哈希表是否存在这个字段名。
## 相关文档
- [Remove](Remove.md)

View File

@@ -0,0 +1,21 @@
# ScriptFieldStorage::Deserialize
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptFieldStorage.h`
## 签名
```cpp
void Deserialize(std::istream& is);
```
## 当前实现行为
先把整个输入流读入字符串,再转交 [DeserializeFromString](DeserializeFromString.md)。
## 相关文档
- [Serialize](Serialize.md)

View File

@@ -0,0 +1,29 @@
# ScriptFieldStorage::DeserializeFromString
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptFieldStorage.h`
## 签名
```cpp
void DeserializeFromString(const std::string& data);
```
## 当前实现行为
- 先清空已有字段。
- 按行读取。
- 只接受以 `field=` 开头的行。
- 必须存在两个 `|` 分隔符。
- 类型名解析失败或值解析失败时,该行会被跳过。
## 设计含义
当前恢复策略偏容错而不是强校验,更适合场景文件向前兼容和调试阶段手工修复。
## 相关文档
- [SerializeToString](SerializeToString.md)

View File

@@ -0,0 +1,22 @@
# ScriptFieldStorage::FindField
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptFieldStorage.h`
## 签名
```cpp
const StoredScriptField* FindField(const std::string& fieldName) const;
StoredScriptField* FindField(const std::string& fieldName);
```
## 当前实现行为
按字段名在内部 `unordered_map` 里查找,找不到返回 `nullptr`
## 相关文档
- [Contains](Contains.md)

View File

@@ -0,0 +1,21 @@
# ScriptFieldStorage::GetFieldCount
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptFieldStorage.h`
## 签名
```cpp
size_t GetFieldCount() const;
```
## 当前实现行为
内联返回内部字段表元素数量。
## 相关文档
- [GetFieldNames](GetFieldNames.md)

View File

@@ -0,0 +1,26 @@
# ScriptFieldStorage::GetFieldNames
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptFieldStorage.h`
## 签名
```cpp
std::vector<std::string> GetFieldNames() const;
```
## 当前实现行为
- 收集所有字段名。
- 在返回前做字典序排序。
## 设计意义
这保证序列化输出顺序稳定,可重复,便于 diff 与测试。
## 相关文档
- [SerializeToString](SerializeToString.md)

View File

@@ -0,0 +1,22 @@
# ScriptFieldStorage::Remove
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptFieldStorage.h`
## 签名
```cpp
bool Remove(const std::string& fieldName);
```
## 当前实现行为
删除成功返回 `true`,字段不存在返回 `false`
## 相关文档
- [Contains](Contains.md)
- [Clear](Clear.md)

View File

@@ -0,0 +1,48 @@
# ScriptFieldStorage
**命名空间**: `XCEngine::Scripting`
**类型**: `class`
**头文件**: `XCEngine/Scripting/ScriptFieldStorage.h`
**描述**: 以字段名为键保存脚本字段值的本地缓存容器。
## 概览
`ScriptFieldStorage` 是当前脚本系统的数据缓冲层。它保存的不是“任意运行时变量”,而是需要在原生侧被识别、查询、序列化和可能回写的一组字段。
## 设计要点
- 用字段名映射到 `StoredScriptField`,读写简单直接。
- 用模板 `SetFieldValue` / `TryGetFieldValue` 提供方便访问,同时保留显式类型版本。
- `GetFieldNames()` 始终返回排序后的名字,保证序列化稳定性。
- 反序列化会先清空旧数据,再导入新数据,避免旧字段残留。
## 当前实现边界
- 不是线程安全容器。
- 不做类型自动转换。
- 遇到非法反序列化行时会跳过,而不是抛异常中断整个恢复流程。
## 公开方法
| 方法 | 说明 |
|------|------|
| [SetFieldValue](SetFieldValue.md) | 写入字段。 |
| [TryGetFieldValue](TryGetFieldValue.md) | 读取字段。 |
| [FindField](FindField.md) | 按名称查找底层存储项。 |
| [Contains](Contains.md) | 判断字段是否存在。 |
| [Remove](Remove.md) | 删除字段。 |
| [Clear](Clear.md) | 清空所有字段。 |
| [GetFieldCount](GetFieldCount.md) | 返回字段数。 |
| [GetFieldNames](GetFieldNames.md) | 返回排序后的字段名列表。 |
| [SerializeToString](SerializeToString.md) | 序列化为文本。 |
| [DeserializeFromString](DeserializeFromString.md) | 从文本恢复。 |
| [Serialize](Serialize.md) | 写入输出流。 |
| [Deserialize](Deserialize.md) | 从输入流恢复。 |
## 相关文档
- [ScriptField](../ScriptField/ScriptField.md)
- [ScriptComponent](../ScriptComponent/ScriptComponent.md)

View File

@@ -0,0 +1,21 @@
# ScriptFieldStorage::Serialize
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptFieldStorage.h`
## 签名
```cpp
void Serialize(std::ostream& os) const;
```
## 当前实现行为
直接把 [SerializeToString](SerializeToString.md) 的结果写入输出流。
## 相关文档
- [Deserialize](Deserialize.md)

View File

@@ -0,0 +1,27 @@
# ScriptFieldStorage::SerializeToString
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptFieldStorage.h`
## 签名
```cpp
std::string SerializeToString() const;
```
## 当前实现行为
当前按逐行文本格式输出:
```text
field=<escapedName>|<typeName>|<serializedValue>
```
字段顺序由 [GetFieldNames](GetFieldNames.md) 保证稳定。
## 相关文档
- [DeserializeFromString](DeserializeFromString.md)

View File

@@ -0,0 +1,29 @@
# ScriptFieldStorage::SetFieldValue
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptFieldStorage.h`
## 签名
```cpp
template<typename T>
bool SetFieldValue(const std::string& fieldName, const T& value);
bool SetFieldValue(
const std::string& fieldName,
ScriptFieldType type,
const ScriptFieldValue& value);
```
## 当前实现行为
- 模板重载会先通过 `ScriptFieldTypeResolver<T>` 推导类型。
- 显式重载会拒绝空字段名或类型/值不兼容的输入。
- 成功时覆盖或写入对应字段。
## 相关文档
- [TryGetFieldValue](TryGetFieldValue.md)

Some files were not shown because too many files have changed in this diff Show More