GFramework/docs/zh-CN/source-generators/schema-config-generator.md
gewuyou a92b37b022 docs(source-generators): 补充生成器专题覆盖并更新进度
- 新增 Schema 配置生成器专题页,补充输入契约、生成物与诊断边界

- 更新 source-generators、API 参考与 CQRS 文档,说明共享支撑层阅读路线与 fallback 分层

- 更新 documentation-full-coverage-governance 的 tracking 和 trace,记录批次指标与验证结果
2026-04-30 16:27:50 +08:00

7.4 KiB
Raw Blame History

title, description
title description
Schema 配置生成器 说明 GFramework.Game.SourceGenerators 如何从 schema 生成配置类型、表包装和聚合注册入口。

Schema 配置生成器

GFramework.Game.SourceGenerators 会把消费者项目里的 schemas/**/*.schema.json 读入编译期管线,并生成:

  • 强类型配置类型
  • 对应的表包装类型
  • 单表绑定辅助代码
  • 聚合注册目录与 RegisterAllGeneratedConfigTables(...) 扩展入口

如果你当前目标是“先把配置系统接进项目”,先看 游戏内容配置系统。这页更适合在你已经决定使用 Game.SourceGenerators 之后,继续确认 schema 输入契约、生成结果和常见诊断边界。

它解决什么问题

相比只写 YAML 和运行时加载代码,这个生成器把三件事前移到了编译期:

  • 把 schema 转成 Config 类型,让业务代码直接拿到强类型字段和 XML 文档
  • 为运行时表生成包装层,让 GetTryGet、按字段查找等入口保持稳定
  • 汇总当前项目中所有 schema 的注册信息,避免 schema 数量增长后继续手写逐表注册

这也是 GFramework.Game 配置运行时、VS Code 配置工具和 schema 约束能够共享同一份结构定义的基础。

最小接入路径

NuGet 安装保持运行时包与生成器包版本一致,并把生成器声明为编译期依赖:

<ItemGroup>
  <PackageReference Include="GeWuYou.GFramework.Game" Version="x.y.z" />
  <PackageReference Include="GeWuYou.GFramework.Game.SourceGenerators"
                    Version="x.y.z"
                    PrivateAssets="all"
                    ExcludeAssets="runtime" />
</ItemGroup>

默认情况下,包内 targets 会自动把 schemas/**/*.schema.json 纳入 AdditionalFiles。如果你的 schema 目录不是 schemas/,可以在项目文件里覆盖:

<PropertyGroup>
  <GFrameworkConfigSchemaDirectory>GameSchemas</GFrameworkConfigSchemaDirectory>
</PropertyGroup>

输入约定

schema 根对象

当前生成器要求每个 schema 都满足这些基本约束:

  • 顶层 type 必须是 object
  • 必须声明必填 id 字段
  • id 目前只支持 integerstring
  • schema 文件名与属性名都必须能稳定映射到合法的 C# 标识符

最小示例:

{
  "title": "Monster Config",
  "type": "object",
  "required": ["id", "name"],
  "properties": {
    "id": {
      "type": "integer"
    },
    "name": {
      "type": "string"
    }
  }
}

路径与索引元数据

除了标准 JSON Schema 字段,当前还支持几个会直接影响生成结果的扩展元数据:

  • x-gframework-config-path
    • 覆盖默认配置目录;值必须是相对路径,且不能包含 ... 或绝对路径段
  • x-gframework-index
    • 为顶层必填、非主键、非引用的标量字段生成 FindBy... / TryFindFirstBy... 查找入口
  • x-gframework-ref-table
    • 为字段补充跨表引用语义,并把这部分信息写入生成的绑定元数据

如果某个字段不满足 lookup index 的安全条件,生成器会直接报诊断,而不是静默生成一个容易失真的查询入口。

当前稳定约束子集

从源码和快照测试看,当前共享子集已经覆盖:

  • 标量、嵌套对象、对象数组、标量数组
  • defaultenumconst
  • minimummaximumexclusiveMinimumexclusiveMaximummultipleOf
  • minLengthmaxLengthpattern
  • format
    • 当前稳定字符串子集是 datedate-timedurationemailtimeuriuuid
  • minItemsmaxItemsuniqueItemscontainsminContainsmaxContains
  • minPropertiesmaxProperties
  • dependentRequireddependentSchemasallOf
  • 面向对象约束的 if / then / else

这些约束并不一定都会改变生成类型的形状,但会被保留到生成代码文档和绑定元数据里,方便运行时与工具链共享。

会生成什么

monster.schema.json 为例,当前生成器会形成四组稳定输出:

1. 配置类型

例如 MonsterConfig。它承载 schema 字段到 C# 属性的映射,以及对应的 XML 文档。

2. 表包装类型

例如 MonsterTable。它包装运行时 IConfigTable<TKey, TValue>,并在需要时提供生成的查找入口:

public sealed partial class MonsterTable : IConfigTable<int, MonsterConfig>
{
    public MonsterConfig Get(int key) { ... }

    public IReadOnlyList<MonsterConfig> FindByName(string value) { ... }

    public bool TryFindFirstByName(string value, out MonsterConfig? result) { ... }
}

如果字段声明了 x-gframework-index,生成器会优先使用延迟构建的只读索引;否则按当前表快照做确定性的线性扫描,以保持和热重载后的运行时数据一致。

3. 单表绑定辅助

例如 MonsterConfigBindings。这里会保留单表注册所需的表名、schema 路径、配置路径和引用元数据,方便项目侧继续组合自己的启动逻辑。

4. 聚合注册目录

当一个项目里有多个 schema 时,生成器还会汇总出 GeneratedConfigCatalog 与聚合扩展:

loader.RegisterAllGeneratedConfigTables();

如果你需要按表传入额外比较器或做更细粒度控制,还可以使用带 GeneratedConfigRegistrationOptions 的重载。

运行时如何消费这些输出

最常见的消费路径是把生成器输出交给 GameConfigBootstrapYamlConfigLoader

using GFramework.Game.Config;
using GFramework.Game.Config.Generated;

var bootstrap = new GameConfigBootstrap(
    new GameConfigBootstrapOptions
    {
        RootPath = configRootPath,
        ConfigureLoader = static loader => loader.RegisterAllGeneratedConfigTables()
    });

当你需要继续手动拼装运行时,也可以直接用单表绑定或聚合目录做自己的注册封装。这时建议把“启动生命周期”和“业务读取入口”分开,继续沿用 游戏内容配置系统 里的 GameConfigHost / GameConfigRuntime 模板。

常见诊断边界

当前 ConfigSchemaDiagnostics 暴露的错误主要分成四类:

  • schema 根对象或 JSON 读入失败
    • 例如 GF_ConfigSchema_001GF_ConfigSchema_002
  • 主键与类型映射不合法
    • 例如 GF_ConfigSchema_003GF_ConfigSchema_005
  • 生成标识符或路径元数据不安全
    • 例如 GF_ConfigSchema_006GF_ConfigSchema_007
  • 额外约束元数据不合法
    • 例如 GF_ConfigSchema_008GF_ConfigSchema_014

这些边界由 GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs 和快照测试共同覆盖。遇到生成失败时,优先先看诊断 ID再回头核对 schema 本身是否超出当前公开子集。

什么时候优先看这页

适合:

  • 你想确认一个 schema 字段会生成哪些 C# 入口
  • 你要排查 x-gframework-index、路径元数据或标识符冲突
  • 你在做项目级聚合注册,希望知道 GeneratedConfigCatalogRegisterAllGeneratedConfigTables(...) 的边界

不适合:

  • 你只是第一次接入配置运行时
  • 你更关心 GameConfigBootstrap、热重载、Godot 资源路径或 VS Code 配置工具

这些采用问题分别回到: