docs: sync api and planning docs

This commit is contained in:
2026-04-08 16:07:03 +08:00
parent 08c3278e10
commit 31756847ab
1826 changed files with 44502 additions and 29645 deletions

View File

@@ -4,51 +4,102 @@
**类型**: `submodule`
**描述**: 收纳基于 Mono 的托管脚本运行时实现。
**描述**: 收纳基于 Mono 的托管脚本运行时实现,以及当前脚本字段发现、默认值读取与运行时桥接的 Mono 后端文档
## 概览
`docs/api/XCEngine/Scripting/Mono` 对应 `engine/include/XCEngine/Scripting/Mono` 子目录。它不是独立命名空间,而是脚本模块按后端实现拆出的子目录。
`docs/api/XCEngine/Scripting/Mono` 对应 `engine/include/XCEngine/Scripting/Mono`。它不是独立命名空间,而是脚本系统按运行时后端拆出的子目录。
当前这里唯一的公开类型是 [MonoScriptRuntime](MonoScriptRuntime/MonoScriptRuntime.md)。它负责:
当前这里的核心公开类型是 [MonoScriptRuntime](MonoScriptRuntime/MonoScriptRuntime.md)。它负责:
- 初始化 Mono root domain app domain
- 解析 `MonoScriptRuntime::Settings`,推导程序集目录、脚本核心程序集和游戏程序集路径。
- 加载 `XCEngine.ScriptCore.dll``GameScripts.dll`
- 发现应用程序集中的非抽象 `MonoBehaviour` 子类,并缓存支持的公共实例字段与生命周期方法。
- `ScriptComponent` 创建托管实例注入 `GameObject`/`ScriptComponent` 上下文,并在生命周期后同步字段。
- 初始化 Mono root domain / app domain
- 加载 `XCEngine.ScriptCore.dll``GameScripts.dll`
- 发现应用程序集中的非抽象 `MonoBehaviour` 子类
- 构建字段元数据与字段默认值查询能力
- 创建脚本实例注入上下文并调用生命周期
- 通过 internal call 把 `Debug``Time``Input``GameObject``Transform` 等托管 API 接回原生实现
## 为什么单独分目录
## 字段发现模型
把 Mono 运行时放进独立子目录,而不是直接塞进 `Scripting` 根目录,有两个直接好处:
这一轮最重要的语义更新,是当前 Mono 后端已经不再等同于“只发现 public 实例字段”。
- 可以清楚区分“脚本系统公共契约”和“具体后端实现”。
- 以后如果接入别的脚本后端,这里天然就是平行扩展点。
当前真实规则是:
## 程序集来源
- 先排除:
- `static`
- `const / literal`
- `readonly / init-only`
- 然后接受:
- `public` 实例字段
- 或者标了 `[SerializeField]``private` 实例字段
- 最后再按当前支持的字段类型过滤
当前 Mono 后端既支持测试程序集目录,也支持项目资产脚本程序集目录
这意味着
- `managed/CMakeLists.txt` 会构建基础 `XCEngine.ScriptCore.dll` `GameScripts.dll`
- 同一份 CMake 还会把 `project/Assets/**/*.cs` 编译到 `project/Library/ScriptAssemblies/GameScripts.dll`
- `tests/scripting/test_project_script_assembly.cpp` 已验证运行时能从项目程序集目录发现 `ProjectScripts.ProjectScriptProbe` 及其默认字段值。
- `FieldMetadataProbe.Health` / `Speed` / `Label` 这类 `public` 字段会被发现
- `FieldMetadataProbe.HiddenFlag` 这种 `[SerializeField] private` 字段也会被发现
- `IgnoredPrivateCounter` 这类未标注的 `private` 字段仍然会被忽略
- `SharedCounter` 这类 `static` 字段会被忽略
- `UnsupportedRotation` 这类当前不支持的类型也会被忽略
## 为什么要支持 `[SerializeField] private`
这是一个很典型的 Unity 风格设计,但它的价值不只是“和 Unity 看齐”。更重要的是它解决了工程里的两个真实矛盾:
- 你希望字段能被序列化、能被 Inspector 或场景存储驱动
- 但你又不希望把这个字段暴露成脚本类的公开 API
支持 `[SerializeField] private` 的好处包括:
- 保留封装边界,不必为了可持久化而把内部状态全部改成 `public`
- 更适合后续重构,减少脚本 API 面被外部任意依赖
- 和商业引擎用户的认知模型一致,降低脚本作者迁移成本
而继续忽略“未标注的 private 字段”,则能防止把纯运行时内部状态意外持久化。
## 为什么要排除 `readonly`
当前字段同步模型要求:
- 运行前可以把 `ScriptFieldStorage` 里的覆盖值写回托管实例
- 运行后可以把托管实例里的值同步回本地存储
`readonly` 字段不适合承担这类双向同步职责,因此当前实现把 `init-only` 直接排除。这是一个偏工程安全的取舍。
## 程序集事实来源
当前 Mono 后端的类发现和字段发现,依赖的是“编译后的程序集事实”,而不是直接扫描 `.cs` 源文件目录:
- `XCEngine.ScriptCore.dll` 提供托管基类和属性
- `GameScripts.dll` 提供应用层脚本类
这和商业引擎常见的做法一致Inspector 列表、字段元数据、默认值读取和真正实例化,都应该基于同一份已编译产物。
## 测试锚点
当前行为直接受到以下测试约束:
- `ClassFieldMetadataListsSupportedPublicInstanceFields`
- `ClassFieldDefaultValueQueryReturnsSerializeFieldPrivateInitializers`
- `SerializeFieldPrivateFieldsApplyStoredValuesAndPersistAcrossSceneRoundTrip`
- `test_project_script_assembly.cpp` 里的项目程序集发现与默认值读取用例
## 当前实现边界
- 当前只实现了 Mono 后端,没有并列的 IL2CPPLua 自研 VM 后端。
- 目录里只有一个 public header说明当前重点仍然是把一条 Mono 托管链路跑通
- 类发现只扫描当前应用程序集里的非抽象 `MonoBehaviour` 子类,不会把工具类或抽象基类暴露给脚本绑定 UI
- 字段发现只接受受支持类型的 `public``static` 实例字段
- internal call 目前已覆盖 `GameObject``Transform``Camera``Light``MeshFilter``MeshRenderer`、日志和时间桥接,但远不是完整编辑器级脚本 API 面。
- 当前只 Mono 后端,没有并列的 IL2CPP / Lua / 自研 VM 后端。
- 字段发现只扫描应用程序集里的非抽象 `MonoBehaviour` 子类
- `[SerializeField] private` 已支持,但“未标注 private”“`readonly`”“不支持类型”仍然不会进入字段模型
- 项目脚本能否被发现,取决于它是否成功进入 `GameScripts.dll`,而不是取决于源文件是否存在于目录里
## 头文件
- [MonoScriptRuntime](MonoScriptRuntime/MonoScriptRuntime.md) - `MonoScriptRuntime.h`
- [MonoScriptRuntime](MonoScriptRuntime/MonoScriptRuntime.md)
## 相关指南
- [Scripting Runtime And Field Model](../../../_guides/Scripting/Scripting-Runtime-And-Field-Model.md)
- [Project Script Assembly And Field Sync](../../../_guides/Scripting/Project-Script-Assembly-And-Field-Sync.md)
- [Game View Runtime Input Bridge](../../../_guides/Editor/Game-View-Runtime-Input-Bridge.md)
## 相关文档