Skip to content

Latest commit

 

History

History
236 lines (166 loc) · 20.2 KB

Inno.Scripting.Api.md

File metadata and controls

236 lines (166 loc) · 20.2 KB

Inno.Scripting.Api

Scripting 索引 · Extensibility Modules · Editor Scripting · Wiki 首页

Inno.Scripting.Api 是一个极小、无 Roslyn 依赖的声明程序集。它定义“哪些真实引擎类型属于脚本 API”的 assembly-level attribute,以及由领域基类声明脚本派生类型类别的 type-level metadata;脚本发现、reference assembly 生成与编译由 Scripting Compiler 负责,热重载由共享 generation 流程与宿主协调。

设计边界

  • 每个参与脚本 API 的 feature 项目只保留一个 Properties/ScriptingApi.cs。清单通常导出本项目类型,也可以选择性导出依赖项目的类型;不设置反向依赖全部模块的中央清单项目。
  • 清单必须逐类型显式导出,不允许用“整个 public assembly 都可用”代替。
  • InnoEngine.Scene、InnoEngine.Mathematics 等名称是稳定且可直接 using 的脚本 API namespace;它们映射到一个或多个真实 CLR namespace。
  • InnoEngine.Events 导出 Core Event、EventDispatcher 与 EventHub,上层交互模块复用这组订阅、分发及生命周期契约。
  • 导出会为 IDE 生成逻辑 API facade,但 facade 只是编辑期代码模型。Editor 内的热编译仍将逻辑 namespace 转换为真实类型身份,因此热重载、TypeCatalog 和序列化看到的是真实 Inno.* 类型体系。
  • 该项目不知道源文件目录、Roslyn、程序集加载上下文或 Scene 迁移。

Public API

ScriptingApiScope

值 可见范围
Runtime Inno.GameScripts 和 Inno.EditorScripts。
Editor 仅 Inno.EditorScripts。
Authoring GameScripts/EditorScripts 的创作编译与 IDE 可见;Player 绑定前移除标注使用、派生标注声明及其 namespace import。

Authoring 用于独立 namespace 中的编译期标注及其枚举,不是运行时服务权限。自定义展示标注可以派生公开的标注基类;编译器依据导出清单及符号继承关系处理,不维护 Editor 类型名单。把这类类型当作 Player 的普通字段或业务对象使用会产生编译错误,而不会把 Editor DLL 带入 Player。

ScriptingApiExportAttribute

using System;
using Inno.Scripting.Api;

static ScriptingApiExportAttribute DescribeExport(Type exportedType)
{
    return new ScriptingApiExportAttribute(exportedType, ScriptingApiScope.Runtime);
}

将一个 public runtime 类型加入指定 profile。声明 assembly 不需要拥有该类型,因此上层 feature 可以有选择地导出底层依赖的类型;reference builder 始终按 type.Assembly 生成 runtime reference,CLR 类型身份不会被错误地改成声明 assembly。该实现 namespace 必须存在唯一的 ScriptingApiNamespace 映射。

第二个重载只改变脚本 facade 中的类型名称,最终运行时 IL 仍引用原始 CLR 类型。Editor 会同步处理 IDE reference、普通 using、完全限定类型名和 XML documentation identity。例如:

using Inno.Scripting.Api;

[assembly: ScriptingApiNamespace("Example.Editor", "Example.Implementation", ScriptingApiScope.Editor)]
[assembly: ScriptingApiExport(typeof(Example.Implementation.ImplementationType), "PublicApiName", ScriptingApiScope.Editor)]

namespace Example.Implementation
{
    public sealed class ImplementationType { }
}

EditorScripts 看到的是 PublicApiName,Host 和运行时仍使用 ImplementationType。已有 XML 注释会迁移到别名后的 identity;泛型类型不能更名,因为 C# 不支持为开放泛型声明普通 using alias。

清单所有权属于决定公开该能力的 feature,类型的运行时所有权仍属于原程序集。当前 ImGuiIcon 和 NativeImGui 由 Inno.Editor.ImGui 自己导出到 InnoEditor.ImGui,FileBrowser 不再维护别名。

ScriptingApiNamespaceAttribute

using Inno.Scripting.Api;

static ScriptingApiNamespaceAttribute DescribeNamespace()
{
    return new ScriptingApiNamespaceAttribute("Example.Tools", "Example.Implementation", ScriptingApiScope.Editor);
}

把稳定脚本 namespace 映射到真实 namespace。一个脚本 namespace 可以有多个实现 namespace,例如 Scene 同时映射核心类型和 Components:

using Inno.Scripting.Api;

[assembly: ScriptingApiNamespace(
    "InnoEngine.Scene",
    "Inno.Scene",
    ScriptingApiScope.Runtime)]

[assembly: ScriptingApiNamespace(
    "InnoEngine.Scene",
    "Inno.Scene.Components",
    ScriptingApiScope.Runtime)]

脚本可以直接写:

using InnoEngine.Scene;

public sealed class PlayerController : GameBehavior
{
}

Editor 会为 IDE 生成一个真正声明 InnoEngine.Scene.GameBehavior 等编译期类型的 metadata-only facade。它只保留已导出 API,且生成的 IDE csproj 不参考任何真实引擎 DLL,所以 Inno.* 无法被 IDE 解析。

Plugin 源码与 Project 脚本会分别生成 IDE 工程,并通过普通 ProjectReference 连接;两者引用同一逻辑 facade,因此插件派生自 GameBehavior 等类型时,使用方不需要额外引用实现程序集。

运行时热编译不使用 facade 产物;ScriptCompiler 在内存中将已声明的逻辑 using 改写到对应实现 namespace,并使用保留真实程序集身份的裁剪参考集编译。最终 IL 因此仍引用 Inno.Scene.GameBehavior,不会把 facade 类型带入运行时。

脚本直接写 using Inno.Scene; 会得到 INNO2001 错误;使用已导出类型却没有导入对应逻辑 namespace 会得到 INNO2002。这两个诊断同时用于运行时 Roslyn 编译和生成的 IDE 工程。

ScriptingAttachableTypeAttribute

using Inno.Scripting.Api;

[ScriptingAttachableType("example.tool")]
public abstract class ToolBehavior
{
}

领域项目把该 Attribute 放在允许脚本派生、且需要稳定 source-owned Type ID 的根基类上。kind 是非空、由领域定义的 manifest 分类名称;API catalog 从真实领域基类读取 metadata 并构建中立映射,编译器再沿脚本类型的基类链匹配该映射,而不硬编码 Scene、Component、System 或任何具体领域类型名。该设计不依赖裁剪 reference assembly 是否复制 host-only Attribute。

例如 GameBehavior 与 GameSystem 分别声明自己的类别后,Editor Scripting 只依赖这项中立 metadata。将来其他领域增加可附着脚本基类时,只修改该领域基类,无需让 Scripting 项目引用该领域程序集,也无需扩展中央类型名列表。该 Attribute 本身不参与实例迁移,不保存 Type,也不会形成 collectible ALC 的长期引用。

Namespace 导入规则

每个脚本文件必须通过普通 using InnoEngine.* 或 using InnoEditor.* 显式导入自己使用的逻辑 namespace。编译范围导入、隐式导入、MSBuild Using item 和 plugin metadata 注入均被禁止。运行时编译器会把每个文件中的逻辑 namespace 映射为该文件可见的实现 namespace,不会把导入扩散到其他源码文件。

标准 Properties/ScriptingApi.cs

每个项目在自己的 Properties/ScriptingApi.cs 声明逻辑 namespace 和逐类型导出。例如,拥有一个独立数值类型的模块:

using Inno.Scripting.Api;

[assembly: ScriptingApiNamespace(
    "Example.Values",
    "Example.Implementation",
    ScriptingApiScope.Runtime)]

[assembly: ScriptingApiExport(typeof(Example.Implementation.Amount), ScriptingApiScope.Runtime)]

namespace Example.Implementation
{
    public readonly record struct Amount(float value);
}

新增 Rendering 扩展项目时,只在该项目的 Properties/ScriptingApi.cs 声明 InnoEngine.Rendering 及其导出类型;无需修改 ModuleHost、TypeCache 或中央项目名单。

成员可见性

导出单位首先是类型。Editor 在生成裁剪 reference assembly 时只保留 public/protected 签名;若某个成员的签名引用了未导出的非框架类型,该成员不会进入脚本 reference assembly。这避免了通过一个返回内部子系统类型的属性意外扩大 API 闭包。

例如只导出 StableTypeIdAttribute 不会顺带让脚本访问 TypeCatalog、TypeRegistry<TSnapshot> 或 reload context。

常见误区

  • Namespace 导入不是访问权限;真正的边界来自显式 export、IDE 逻辑 facade、运行时裁剪 reference assembly 和逻辑 namespace 分析器。
  • 不要通过生成源码、项目项或 plugin metadata 注入编译范围导入;每个脚本文件都应显式声明依赖。
  • 不要为方便而导出整个 Manager/Registry 程序集。先导出脚本确实需要的最小类型。
  • 不要在多个文件分散 assembly attribute。每个项目唯一的 Properties/ScriptingApi.cs 是可审查的 API 清单。
  • 脚本 API namespace 是稳定的源码契约;真实 CLR namespace 仍决定运行时类型身份。

当前源码公开 API 清单

按类型列出当前 public 与可供外部派生实现使用的 protected 声明。签名包含 nullable、默认参数和泛型约束;源码链接可定位实现。表中的“—”表示该声明没有额外 XML 约束,不能据此推断线程安全或不会失败。生命周期与组合顺序见本页前文。

Inno.Scripting.Api.ScriptingApiExportAttribute

声明 行为与结果 所有权 / 调用约束 失败或限制
public Inno.Scripting.Api.ScriptingApiExportAttribute.ScriptingApiExportAttribute(System.Type type, Inno.Scripting.Api.ScriptingApiScope scope) Creates an explicit script API export.
type:The runtime type exposed to scripts.
scope:The script profile that receives the type.
— System.ArgumentNullException:Thrown when type is null.
public Inno.Scripting.Api.ScriptingApiExportAttribute.ScriptingApiExportAttribute(System.Type type, string name, Inno.Scripting.Api.ScriptingApiScope scope) Creates an explicit script API export with a script-facing type name.
type:The runtime type exposed to scripts.
name:The type name presented by the script facade.
scope:The script profile that receives the type.
— System.ArgumentNullException:Thrown when type is null.
System.ArgumentException:Thrown when name is empty.
public string Inno.Scripting.Api.ScriptingApiExportAttribute.name { get; } Gets the type name presented by the script facade. — —
public Inno.Scripting.Api.ScriptingApiScope Inno.Scripting.Api.ScriptingApiExportAttribute.scope { get; } Gets the script profile that receives the type. — —
public System.Type Inno.Scripting.Api.ScriptingApiExportAttribute.type { get; } Gets the runtime type exposed to scripts. — —
public sealed class Inno.Scripting.Api.ScriptingApiExportAttribute : System.Attribute Exports one public runtime type to a script compilation profile. The declaration assembly does not need to own the exported type. Feature projects may expose selected types from lower-level dependencies while the generated runtime reference preserves the exported type's original assembly identity. —

Inno.Scripting.Api.ScriptingApiIgnoreAttribute

声明 行为与结果 所有权 / 调用约束 失败或限制
public Inno.Scripting.Api.ScriptingApiIgnoreAttribute.ScriptingApiIgnoreAttribute() C# 隐式构造函数;按类型声明执行字段初始化和基类构造。 — —
public sealed class Inno.Scripting.Api.ScriptingApiIgnoreAttribute : System.Attribute Explicitly excludes one otherwise visible member from generated scripting reference assemblies. — —

Inno.Scripting.Api.ScriptingApiNamespaceAttribute

声明 行为与结果 所有权 / 调用约束 失败或限制
public Inno.Scripting.Api.ScriptingApiNamespaceAttribute.ScriptingApiNamespaceAttribute(string name, string implementationNamespace, Inno.Scripting.Api.ScriptingApiScope scope) Creates a script API namespace mapping.
name:The stable script API namespace, such as InnoEngine.Scene.
implementationNamespace:The CLR namespace containing exported runtime types.
scope:The script profile that receives the mapping.
— —
public string Inno.Scripting.Api.ScriptingApiNamespaceAttribute.implementationNamespace { get; } Gets the CLR namespace that implements the script API namespace. — —
public string Inno.Scripting.Api.ScriptingApiNamespaceAttribute.name { get; } Gets the stable script API namespace. — —
public Inno.Scripting.Api.ScriptingApiScope Inno.Scripting.Api.ScriptingApiNamespaceAttribute.scope { get; } Gets the script profile that receives the mapping. — —
public sealed class Inno.Scripting.Api.ScriptingApiNamespaceAttribute : System.Attribute Maps a stable script-facing API namespace to one CLR implementation namespace. Multiple implementation namespaces can map to the same script API namespace. This keeps script organization stable without introducing wrapper types with different runtime identities. A feature assembly may declare a mapping for a dependency namespace when that feature owns the decision to expose selected dependency types. —

Inno.Scripting.Api.ScriptingApiScope

声明 行为与结果 所有权 / 调用约束 失败或限制
Inno.Scripting.Api.ScriptingApiScope.Authoring = 2 Exposes compile-time annotations to game and editor scripts. Player compilation erases their applications and derived annotation declarations before binding to target assemblies. — —
Inno.Scripting.Api.ScriptingApiScope.Editor = 1 Exposes the API only to editor scripts. — —
Inno.Scripting.Api.ScriptingApiScope.Runtime = 0 Exposes the API to both game and editor scripts. — —
public enum Inno.Scripting.Api.ScriptingApiScope : int Identifies the script compilation profile that receives an exported API. — —

Inno.Scripting.Api.ScriptingAttachableTypeAttribute

声明 行为与结果 所有权 / 调用约束 失败或限制
public Inno.Scripting.Api.ScriptingAttachableTypeAttribute.ScriptingAttachableTypeAttribute(string kind) Creates attachable script-type metadata for one extensible base class.
kind:The non-empty domain-defined kind written to script type manifests and diagnostics.
— System.ArgumentException:Thrown when kind is empty or contains only whitespace.
public string Inno.Scripting.Api.ScriptingAttachableTypeAttribute.kind { get; } Gets the domain-defined attachable type kind recorded in script manifests. — —
public sealed class Inno.Scripting.Api.ScriptingAttachableTypeAttribute : System.Attribute Marks a script API base type whose concrete script-derived types require stable source-owned identity metadata. — —

项目依赖