mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-06 16:16:44 +08:00
feat(config): 添加AI-First配置系统及文档
- 引入YAML配置源文件支持 - 实现JSON Schema结构描述功能 - 提供一对象一文件的目录组织方式 - 添加运行时只读查询能力 - 实现Source Generator生成配置类型和表包装 - 集成VS Code插件提供配置浏览和编辑功能 - 添加开发期热重载支持 - 提供跨表引用校验机制 - 创建配置生成器约定和绑定辅助类 - 添加详细的中文文档说明 - 实现集成测试验证生成器功能
This commit is contained in:
parent
ec5153f452
commit
61cc7eaa6d
@ -91,9 +91,16 @@ public class GeneratedConfigConsumerIntegrationTests
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(MonsterConfigBindings.ConfigDomain, Is.EqualTo("monster"));
|
||||
Assert.That(MonsterConfigBindings.TableName, Is.EqualTo("monster"));
|
||||
Assert.That(MonsterConfigBindings.ConfigRelativePath, Is.EqualTo("monster"));
|
||||
Assert.That(MonsterConfigBindings.SchemaRelativePath, Is.EqualTo("schemas/monster.schema.json"));
|
||||
Assert.That(MonsterConfigBindings.Metadata.ConfigDomain, Is.EqualTo(MonsterConfigBindings.ConfigDomain));
|
||||
Assert.That(MonsterConfigBindings.Metadata.TableName, Is.EqualTo(MonsterConfigBindings.TableName));
|
||||
Assert.That(MonsterConfigBindings.Metadata.ConfigRelativePath,
|
||||
Is.EqualTo(MonsterConfigBindings.ConfigRelativePath));
|
||||
Assert.That(MonsterConfigBindings.Metadata.SchemaRelativePath,
|
||||
Is.EqualTo(MonsterConfigBindings.SchemaRelativePath));
|
||||
Assert.That(table.Count, Is.EqualTo(2));
|
||||
Assert.That(table.Get(1).Name, Is.EqualTo("Slime"));
|
||||
Assert.That(table.Get(2).Hp, Is.EqualTo(30));
|
||||
|
||||
@ -9,20 +9,51 @@ namespace GFramework.Game.Config.Generated;
|
||||
/// </summary>
|
||||
public static class MonsterConfigBindings
|
||||
{
|
||||
/// <summary>
|
||||
/// Groups the schema-derived metadata constants so consumer code can reuse one stable entry point.
|
||||
/// </summary>
|
||||
public static class Metadata
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the logical config domain derived from the schema base name. The current runtime convention keeps this value aligned with the generated table name.
|
||||
/// </summary>
|
||||
public const string ConfigDomain = "monster";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the runtime registration name of the generated config table.
|
||||
/// </summary>
|
||||
public const string TableName = "monster";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the config directory path expected by the generated registration helper.
|
||||
/// </summary>
|
||||
public const string ConfigRelativePath = "monster";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the schema file path expected by the generated registration helper.
|
||||
/// </summary>
|
||||
public const string SchemaRelativePath = "schemas/monster.schema.json";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the logical config domain derived from the schema base name. The current runtime convention keeps this value aligned with the generated table name.
|
||||
/// </summary>
|
||||
public const string ConfigDomain = Metadata.ConfigDomain;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the runtime registration name of the generated config table.
|
||||
/// </summary>
|
||||
public const string TableName = "monster";
|
||||
public const string TableName = Metadata.TableName;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the config directory path expected by the generated registration helper.
|
||||
/// </summary>
|
||||
public const string ConfigRelativePath = "monster";
|
||||
public const string ConfigRelativePath = Metadata.ConfigRelativePath;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the schema file path expected by the generated registration helper.
|
||||
/// </summary>
|
||||
public const string SchemaRelativePath = "schemas/monster.schema.json";
|
||||
public const string SchemaRelativePath = Metadata.SchemaRelativePath;
|
||||
|
||||
/// <summary>
|
||||
/// Registers the generated config table using the schema-derived runtime conventions.
|
||||
@ -40,9 +71,9 @@ public static class MonsterConfigBindings
|
||||
}
|
||||
|
||||
return loader.RegisterTable<int, MonsterConfig>(
|
||||
TableName,
|
||||
ConfigRelativePath,
|
||||
SchemaRelativePath,
|
||||
Metadata.TableName,
|
||||
Metadata.ConfigRelativePath,
|
||||
Metadata.SchemaRelativePath,
|
||||
static config => config.Id,
|
||||
comparer);
|
||||
}
|
||||
@ -60,7 +91,7 @@ public static class MonsterConfigBindings
|
||||
throw new global::System.ArgumentNullException(nameof(registry));
|
||||
}
|
||||
|
||||
return new MonsterTable(registry.GetTable<int, MonsterConfig>(TableName));
|
||||
return new MonsterTable(registry.GetTable<int, MonsterConfig>(Metadata.TableName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -77,7 +108,7 @@ public static class MonsterConfigBindings
|
||||
throw new global::System.ArgumentNullException(nameof(registry));
|
||||
}
|
||||
|
||||
if (registry.TryGetTable<int, MonsterConfig>(TableName, out var innerTable) && innerTable is not null)
|
||||
if (registry.TryGetTable<int, MonsterConfig>(Metadata.TableName, out var innerTable) && innerTable is not null)
|
||||
{
|
||||
table = new MonsterTable(innerTable);
|
||||
return true;
|
||||
|
||||
@ -650,22 +650,58 @@ public sealed class SchemaConfigGenerator : IIncrementalGenerator
|
||||
builder.AppendLine($"public static class {bindingsClassName}");
|
||||
builder.AppendLine("{");
|
||||
builder.AppendLine(" /// <summary>");
|
||||
builder.AppendLine(
|
||||
" /// Groups the schema-derived metadata constants so consumer code can reuse one stable entry point.");
|
||||
builder.AppendLine(" /// </summary>");
|
||||
builder.AppendLine(" public static class Metadata");
|
||||
builder.AppendLine(" {");
|
||||
builder.AppendLine(" /// <summary>");
|
||||
builder.AppendLine(
|
||||
" /// Gets the logical config domain derived from the schema base name. The current runtime convention keeps this value aligned with the generated table name.");
|
||||
builder.AppendLine(" /// </summary>");
|
||||
builder.AppendLine(
|
||||
$" public const string ConfigDomain = {SymbolDisplay.FormatLiteral(schema.TableRegistrationName, true)};");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine(" /// <summary>");
|
||||
builder.AppendLine(" /// Gets the runtime registration name of the generated config table.");
|
||||
builder.AppendLine(" /// </summary>");
|
||||
builder.AppendLine(
|
||||
$" public const string TableName = {SymbolDisplay.FormatLiteral(schema.TableRegistrationName, true)};");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine(" /// <summary>");
|
||||
builder.AppendLine(
|
||||
" /// Gets the config directory path expected by the generated registration helper.");
|
||||
builder.AppendLine(" /// </summary>");
|
||||
builder.AppendLine(
|
||||
$" public const string ConfigRelativePath = {SymbolDisplay.FormatLiteral(schema.ConfigRelativePath, true)};");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine(" /// <summary>");
|
||||
builder.AppendLine(" /// Gets the schema file path expected by the generated registration helper.");
|
||||
builder.AppendLine(" /// </summary>");
|
||||
builder.AppendLine(
|
||||
$" public const string SchemaRelativePath = {SymbolDisplay.FormatLiteral(schema.SchemaRelativePath, true)};");
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine(" /// <summary>");
|
||||
builder.AppendLine(
|
||||
" /// Gets the logical config domain derived from the schema base name. The current runtime convention keeps this value aligned with the generated table name.");
|
||||
builder.AppendLine(" /// </summary>");
|
||||
builder.AppendLine(" public const string ConfigDomain = Metadata.ConfigDomain;");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine(" /// <summary>");
|
||||
builder.AppendLine(" /// Gets the runtime registration name of the generated config table.");
|
||||
builder.AppendLine(" /// </summary>");
|
||||
builder.AppendLine(
|
||||
$" public const string TableName = {SymbolDisplay.FormatLiteral(schema.TableRegistrationName, true)};");
|
||||
builder.AppendLine(" public const string TableName = Metadata.TableName;");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine(" /// <summary>");
|
||||
builder.AppendLine(" /// Gets the config directory path expected by the generated registration helper.");
|
||||
builder.AppendLine(" /// </summary>");
|
||||
builder.AppendLine(
|
||||
$" public const string ConfigRelativePath = {SymbolDisplay.FormatLiteral(schema.ConfigRelativePath, true)};");
|
||||
builder.AppendLine(" public const string ConfigRelativePath = Metadata.ConfigRelativePath;");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine(" /// <summary>");
|
||||
builder.AppendLine(" /// Gets the schema file path expected by the generated registration helper.");
|
||||
builder.AppendLine(" /// </summary>");
|
||||
builder.AppendLine(
|
||||
$" public const string SchemaRelativePath = {SymbolDisplay.FormatLiteral(schema.SchemaRelativePath, true)};");
|
||||
builder.AppendLine(" public const string SchemaRelativePath = Metadata.SchemaRelativePath;");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine(" /// <summary>");
|
||||
builder.AppendLine(
|
||||
@ -688,9 +724,9 @@ public sealed class SchemaConfigGenerator : IIncrementalGenerator
|
||||
builder.AppendLine();
|
||||
builder.AppendLine(
|
||||
$" return loader.RegisterTable<{schema.KeyClrType}, {schema.ClassName}>(");
|
||||
builder.AppendLine(" TableName,");
|
||||
builder.AppendLine(" ConfigRelativePath,");
|
||||
builder.AppendLine(" SchemaRelativePath,");
|
||||
builder.AppendLine(" Metadata.TableName,");
|
||||
builder.AppendLine(" Metadata.ConfigRelativePath,");
|
||||
builder.AppendLine(" Metadata.SchemaRelativePath,");
|
||||
builder.AppendLine($" static config => config.{schema.KeyPropertyName},");
|
||||
builder.AppendLine(" comparer);");
|
||||
builder.AppendLine(" }");
|
||||
@ -711,7 +747,7 @@ public sealed class SchemaConfigGenerator : IIncrementalGenerator
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine(
|
||||
$" return new {schema.TableName}(registry.GetTable<{schema.KeyClrType}, {schema.ClassName}>(TableName));");
|
||||
$" return new {schema.TableName}(registry.GetTable<{schema.KeyClrType}, {schema.ClassName}>(Metadata.TableName));");
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine(" /// <summary>");
|
||||
@ -733,7 +769,7 @@ public sealed class SchemaConfigGenerator : IIncrementalGenerator
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine(
|
||||
$" if (registry.TryGetTable<{schema.KeyClrType}, {schema.ClassName}>(TableName, out var innerTable) && innerTable is not null)");
|
||||
$" if (registry.TryGetTable<{schema.KeyClrType}, {schema.ClassName}>(Metadata.TableName, out var innerTable) && innerTable is not null)");
|
||||
builder.AppendLine(" {");
|
||||
builder.AppendLine($" table = new {schema.TableName}(innerTable);");
|
||||
builder.AppendLine(" return true;");
|
||||
|
||||
@ -103,11 +103,21 @@ var slime = monsterTable.Get(1);
|
||||
|
||||
这组辅助会把以下约定固化到生成代码里:
|
||||
|
||||
- 配置域常量,例如 `MonsterConfigBindings.ConfigDomain`
|
||||
- 表注册名,例如 `monster`
|
||||
- 配置目录相对路径,例如 `monster`
|
||||
- schema 相对路径,例如 `schemas/monster.schema.json`
|
||||
- 主键提取逻辑,例如 `config => config.Id`
|
||||
|
||||
如果你希望把这些约定作为一个统一入口传递或复用,也可以优先读取 `MonsterConfigBindings.Metadata` 下的常量:
|
||||
|
||||
```csharp
|
||||
var domain = MonsterConfigBindings.Metadata.ConfigDomain;
|
||||
var tableName = MonsterConfigBindings.Metadata.TableName;
|
||||
var configPath = MonsterConfigBindings.Metadata.ConfigRelativePath;
|
||||
var schemaPath = MonsterConfigBindings.Metadata.SchemaRelativePath;
|
||||
```
|
||||
|
||||
如果你需要自定义目录、表名或 key selector,仍然可以直接调用 `YamlConfigLoader.RegisterTable(...)` 原始重载。
|
||||
|
||||
## 运行时校验行为
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user