GeWuYou 43b95c7513 docs(config): 添加游戏内容配置系统完整文档
- 新增配置系统架构说明,涵盖 YAML 源文件、JSON Schema 结构描述、运行时只读查询等核心功能
- 完善推荐目录结构和 Schema 示例,包括怪物、物品配置表的标准定义方式
- 提供完整的接入模板,包含 csproj 配置、GameConfigHost 生命周期管理、GameConfigRuntime 读取入口
- 添加运行时校验行为说明,支持必填字段、类型匹配、数值范围、字符串长度、正则表达式、数组长度等多种约束
- 集成跨表引用功能,支持通过 x-gframework-ref-table 声明关联关系并进行有效性检查
- 添加开发期热重载支持,可自动监听配置目录和 schema 文件变更并重载对应表格
- 提供 VS Code 工具集成说明,包括配置浏览、raw 编辑、schema 打开、表单入口等功能
- 补充生成器接入约定,从 *.schema.json 自动生成配置类型、表包装、注册辅助等代码
- 添加完整的 Analyzer 规则文档,涵盖 GF_ConfigSchema_001 到 GF_ConfigSchema_008 等错误诊断码
- 增加单元测试验证,确保消费者项目可以正常使用生成的聚合注册辅助和强类型访问入口
2026-04-08 09:32:00 +08:00

191 lines
8.2 KiB
Plaintext

// <auto-generated />
#nullable enable
namespace GFramework.Game.Config.Generated;
/// <summary>
/// Auto-generated table wrapper for schema file 'monster.schema.json'.
/// The wrapper keeps generated call sites strongly typed while delegating actual storage to the runtime config table implementation.
/// </summary>
public sealed partial class MonsterTable : global::GFramework.Game.Abstractions.Config.IConfigTable<int, MonsterConfig>
{
private readonly global::GFramework.Game.Abstractions.Config.IConfigTable<int, MonsterConfig> _inner;
private readonly global::System.Lazy<global::System.Collections.Generic.IReadOnlyDictionary<string, global::System.Collections.Generic.IReadOnlyList<MonsterConfig>>> _nameIndex;
/// <summary>
/// Creates a generated table wrapper around the runtime config table instance.
/// </summary>
/// <param name="inner">The runtime config table instance.</param>
public MonsterTable(global::GFramework.Game.Abstractions.Config.IConfigTable<int, MonsterConfig> inner)
{
_inner = inner ?? throw new global::System.ArgumentNullException(nameof(inner));
_nameIndex = new global::System.Lazy<global::System.Collections.Generic.IReadOnlyDictionary<string, global::System.Collections.Generic.IReadOnlyList<MonsterConfig>>>(
BuildNameIndex,
global::System.Threading.LazyThreadSafetyMode.ExecutionAndPublication);
}
/// <inheritdoc />
public global::System.Type KeyType => _inner.KeyType;
/// <inheritdoc />
public global::System.Type ValueType => _inner.ValueType;
/// <inheritdoc />
public int Count => _inner.Count;
/// <inheritdoc />
public MonsterConfig Get(int key)
{
return _inner.Get(key);
}
/// <inheritdoc />
public bool TryGet(int key, out MonsterConfig? value)
{
return _inner.TryGet(key, out value);
}
/// <inheritdoc />
public bool ContainsKey(int key)
{
return _inner.ContainsKey(key);
}
/// <inheritdoc />
public global::System.Collections.Generic.IReadOnlyCollection<MonsterConfig> All()
{
return _inner.All();
}
/// <summary>
/// Builds the exact-match lookup index declared for property 'name'.
/// </summary>
/// <returns>A read-only lookup index keyed by <c>Name</c>.</returns>
private global::System.Collections.Generic.IReadOnlyDictionary<string, global::System.Collections.Generic.IReadOnlyList<MonsterConfig>> BuildNameIndex()
{
return BuildLookupIndex(static config => config.Name);
}
/// <summary>
/// Materializes a read-only exact-match lookup index from the current table snapshot.
/// </summary>
/// <typeparam name="TProperty">Indexed property type.</typeparam>
/// <param name="keySelector">Selects the indexed property from one config entry.</param>
/// <returns>A read-only dictionary whose values preserve snapshot iteration order.</returns>
private global::System.Collections.Generic.IReadOnlyDictionary<TProperty, global::System.Collections.Generic.IReadOnlyList<MonsterConfig>> BuildLookupIndex<TProperty>(
global::System.Func<MonsterConfig, TProperty> keySelector)
where TProperty : notnull
{
var buckets = new global::System.Collections.Generic.Dictionary<TProperty, global::System.Collections.Generic.List<MonsterConfig>>();
// Capture the current table snapshot once so indexed lookups stay deterministic for this wrapper instance.
foreach (var candidate in All())
{
var key = keySelector(candidate);
if (!buckets.TryGetValue(key, out var matches))
{
matches = new global::System.Collections.Generic.List<MonsterConfig>();
buckets.Add(key, matches);
}
matches.Add(candidate);
}
var materialized = new global::System.Collections.Generic.Dictionary<TProperty, global::System.Collections.Generic.IReadOnlyList<MonsterConfig>>(buckets.Count, buckets.Comparer);
foreach (var pair in buckets)
{
materialized.Add(pair.Key, global::System.Array.AsReadOnly(pair.Value.ToArray()));
}
return new global::System.Collections.ObjectModel.ReadOnlyDictionary<TProperty, global::System.Collections.Generic.IReadOnlyList<MonsterConfig>>(materialized);
}
/// <summary>
/// Finds all config entries whose property 'name' equals the supplied value.
/// </summary>
/// <param name="value">The property value to match.</param>
/// <returns>A read-only snapshot containing every matching config entry.</returns>
/// <remarks>
/// This property declares <c>x-gframework-index</c>, so the generated helper resolves matches through a lazily materialized read-only lookup index built from the current table snapshot.
/// </remarks>
public global::System.Collections.Generic.IReadOnlyList<MonsterConfig> FindByName(string value)
{
if (_nameIndex.Value.TryGetValue(value, out var matches))
{
return matches;
}
return global::System.Array.Empty<MonsterConfig>();
}
/// <summary>
/// Tries to find the first config entry whose property 'name' equals the supplied value.
/// </summary>
/// <param name="value">The property value to match.</param>
/// <param name="result">The first matching config entry when lookup succeeds; otherwise <see langword="null" />.</param>
/// <returns><see langword="true" /> when a matching config entry is found; otherwise <see langword="false" />.</returns>
/// <remarks>
/// This property declares <c>x-gframework-index</c>, so the generated helper returns the first element from the lazily materialized exact-match bucket.
/// </remarks>
public bool TryFindFirstByName(string value, out MonsterConfig? result)
{
if (_nameIndex.Value.TryGetValue(value, out var matches) && matches.Count > 0)
{
result = matches[0];
return true;
}
result = null;
return false;
}
/// <summary>
/// Finds all config entries whose property 'hp' equals the supplied value.
/// </summary>
/// <param name="value">The property value to match.</param>
/// <returns>A read-only snapshot containing every matching config entry.</returns>
/// <remarks>
/// The generated helper performs a deterministic linear scan over <see cref="All"/> so it stays compatible with runtime hot reload and does not require secondary index infrastructure.
/// </remarks>
public global::System.Collections.Generic.IReadOnlyList<MonsterConfig> FindByHp(int? value)
{
var matches = new global::System.Collections.Generic.List<MonsterConfig>();
// Scan the current table snapshot on demand so generated helpers stay aligned with reloadable runtime data.
foreach (var candidate in All())
{
if (global::System.Collections.Generic.EqualityComparer<int?>.Default.Equals(candidate.Hp, value))
{
matches.Add(candidate);
}
}
return matches.Count == 0 ? global::System.Array.Empty<MonsterConfig>() : matches.AsReadOnly();
}
/// <summary>
/// Tries to find the first config entry whose property 'hp' equals the supplied value.
/// </summary>
/// <param name="value">The property value to match.</param>
/// <param name="result">The first matching config entry when lookup succeeds; otherwise <see langword="null" />.</param>
/// <returns><see langword="true" /> when a matching config entry is found; otherwise <see langword="false" />.</returns>
/// <remarks>
/// The generated helper walks the same snapshot exposed by <see cref="All"/> and returns the first match in iteration order.
/// </remarks>
public bool TryFindFirstByHp(int? value, out MonsterConfig? result)
{
// Keep the search path allocation-free for the first-match case by exiting as soon as one entry matches.
foreach (var candidate in All())
{
if (global::System.Collections.Generic.EqualityComparer<int?>.Default.Equals(candidate.Hp, value))
{
result = candidate;
return true;
}
}
result = null;
return false;
}
}