docs(config): 添加游戏内容配置系统文档

- 新增 CQRS 架构模式详细文档,包括命令查询职责分离核心概念
- 添加命令、查询、处理器、请求分发器等基本用法示例
- 包含高级用法如通知、管道行为、流式处理等完整功能介绍
- 提供最佳实践指南和常见问题解决方案
- 添加游戏内容配置系统文档,涵盖 YAML 配置源文件和 JSON Schema 结构描述
- 包含推荐目录结构、Schema 示例和 YAML 示例配置
- 提供完整的接入模板,包括 csproj 配置、启动帮助器和运行时读取模板
- 添加 Godot 文本配置桥接、热重载和 Architecture 接入等高级功能说明
This commit is contained in:
GeWuYou 2026-04-16 21:01:01 +08:00
parent 09f751a4f7
commit 0cf4945e78
51 changed files with 416 additions and 293 deletions

View File

@ -1,4 +1,4 @@
namespace GFramework.SourceGenerators.Abstractions.Architectures;
namespace GFramework.Core.SourceGenerators.Abstractions.Architectures;
/// <summary>
/// 标记架构模块类型Source Generator 会根据注册特性生成 <c>Install</c> 方法。

View File

@ -1,4 +1,4 @@
namespace GFramework.SourceGenerators.Abstractions.Architectures;
namespace GFramework.Core.SourceGenerators.Abstractions.Architectures;
/// <summary>
/// 声明架构模块需要自动注册的模型类型。

View File

@ -1,4 +1,4 @@
namespace GFramework.SourceGenerators.Abstractions.Architectures;
namespace GFramework.Core.SourceGenerators.Abstractions.Architectures;
/// <summary>
/// 声明架构模块需要自动注册的系统类型。

View File

@ -1,4 +1,4 @@
namespace GFramework.SourceGenerators.Abstractions.Architectures;
namespace GFramework.Core.SourceGenerators.Abstractions.Architectures;
/// <summary>
/// 声明架构模块需要自动注册的工具类型。

View File

@ -1,4 +1,4 @@
namespace GFramework.SourceGenerators.Abstractions.Bases;
namespace GFramework.Core.SourceGenerators.Abstractions.Bases;
/// <summary>
/// 标记类的优先级,自动生成 <c>GFramework.Core.Abstractions.Bases.IPrioritized</c> 接口实现。

View File

@ -1,4 +1,4 @@
namespace GFramework.SourceGenerators.Abstractions.Enums;
namespace GFramework.Core.SourceGenerators.Abstractions.Enums;
/// <summary>
/// 标注在 enum 上Source Generator 会为该 enum 生成扩展方法。

View File

@ -1,5 +1,5 @@
#nullable enable
namespace GFramework.SourceGenerators.Abstractions.Logging;
namespace GFramework.Core.SourceGenerators.Abstractions.Logging;
/// <summary>
/// 标注在类上Source Generator 会为该类自动生成一个日志记录器字段。

View File

@ -1,4 +1,4 @@
namespace GFramework.SourceGenerators.Abstractions.Rule;
namespace GFramework.Core.SourceGenerators.Abstractions.Rule;
/// <summary>
/// 标记该类需要自动实现 IContextAware

View File

@ -1,4 +1,4 @@
namespace GFramework.SourceGenerators.Abstractions.Rule;
namespace GFramework.Core.SourceGenerators.Abstractions.Rule;
/// <summary>
/// 标记类需要自动推断并注入上下文相关字段。

View File

@ -1,4 +1,4 @@
namespace GFramework.SourceGenerators.Abstractions.Rule;
namespace GFramework.Core.SourceGenerators.Abstractions.Rule;
/// <summary>
/// 标记字段需要自动注入单个模型实例。

View File

@ -1,4 +1,4 @@
namespace GFramework.SourceGenerators.Abstractions.Rule;
namespace GFramework.Core.SourceGenerators.Abstractions.Rule;
/// <summary>
/// 标记字段需要自动注入模型集合。

View File

@ -1,4 +1,4 @@
namespace GFramework.SourceGenerators.Abstractions.Rule;
namespace GFramework.Core.SourceGenerators.Abstractions.Rule;
/// <summary>
/// 标记字段需要自动注入单个服务实例。

View File

@ -1,4 +1,4 @@
namespace GFramework.SourceGenerators.Abstractions.Rule;
namespace GFramework.Core.SourceGenerators.Abstractions.Rule;
/// <summary>
/// 标记字段需要自动注入服务集合。

View File

@ -1,4 +1,4 @@
namespace GFramework.SourceGenerators.Abstractions.Rule;
namespace GFramework.Core.SourceGenerators.Abstractions.Rule;
/// <summary>
/// 标记字段需要自动注入单个系统实例。

View File

@ -1,8 +1,22 @@
namespace GFramework.SourceGenerators.Abstractions.Rule;
namespace GFramework.Core.SourceGenerators.Abstractions.Rule;
/// <summary>
/// 标记字段需要自动注入系统集合。
/// </summary>
/// <remarks>
/// Source Generator 会为标记字段生成从当前架构上下文收集系统实例的注入代码,用于避免在组件内部重复书写
/// <c>GetSystems()</c> 一类的样板访问逻辑。
/// 被标记字段应声明为可承载多个系统实例的类型,例如 <c>IEnumerable&lt;ISystem&gt;</c> 或兼容集合接口。
/// </remarks>
/// <example>
/// <code>
/// public partial class CombatPanel : IContextAware
/// {
/// [GetSystems]
/// private IEnumerable&lt;ISystem&gt; _systems = Array.Empty&lt;ISystem&gt;();
/// }
/// </code>
/// </example>
[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
public sealed class GetSystemsAttribute : Attribute
{

View File

@ -1,4 +1,4 @@
namespace GFramework.SourceGenerators.Abstractions.Rule;
namespace GFramework.Core.SourceGenerators.Abstractions.Rule;
/// <summary>
/// 标记字段需要自动注入工具集合。

View File

@ -1,4 +1,4 @@
namespace GFramework.SourceGenerators.Abstractions.Rule;
namespace GFramework.Core.SourceGenerators.Abstractions.Rule;
/// <summary>
/// 标记字段需要自动注入单个工具实例。

View File

@ -1,9 +1,9 @@
using GFramework.Core.SourceGenerators.Diagnostics;
using GFramework.SourceGenerators.Common.Constants;
using GFramework.SourceGenerators.Diagnostics;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
namespace GFramework.SourceGenerators.Analyzers;
namespace GFramework.Core.SourceGenerators.Analyzers;
/// <summary>
/// 分析 Context Get 使用点是否能在所属架构中找到静态可见的 Model、System、Utility 注册。

View File

@ -1,8 +1,8 @@
using GFramework.SourceGenerators.Diagnostics;
using GFramework.Core.SourceGenerators.Diagnostics;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
namespace GFramework.SourceGenerators.Analyzers;
namespace GFramework.Core.SourceGenerators.Analyzers;
/// <summary>
/// 优先级使用分析器,检测应该使用 GetAllByPriority 而非 GetAll 的场景

View File

@ -1,10 +1,10 @@
using GFramework.SourceGenerators.Abstractions.Architectures;
using GFramework.Core.SourceGenerators.Abstractions.Architectures;
using GFramework.Core.SourceGenerators.Diagnostics;
using GFramework.SourceGenerators.Common.Constants;
using GFramework.SourceGenerators.Common.Diagnostics;
using GFramework.SourceGenerators.Common.Extensions;
using GFramework.SourceGenerators.Diagnostics;
namespace GFramework.SourceGenerators.Architectures;
namespace GFramework.Core.SourceGenerators.Architectures;
/// <summary>
/// 为标记了 <see cref="AutoRegisterModuleAttribute" /> 的模块生成固定顺序的组件注册代码。

View File

@ -1,8 +1,8 @@
using GFramework.Core.SourceGenerators.Diagnostics;
using GFramework.SourceGenerators.Common.Constants;
using GFramework.SourceGenerators.Common.Generator;
using GFramework.SourceGenerators.Diagnostics;
namespace GFramework.SourceGenerators.Bases;
namespace GFramework.Core.SourceGenerators.Bases;
/// <summary>
/// Priority 特性生成器,为标记了 [Priority] 的类自动生成 IPrioritized 接口实现

View File

@ -1,6 +1,6 @@
using GFramework.SourceGenerators.Common.Constants;
namespace GFramework.SourceGenerators.Diagnostics;
namespace GFramework.Core.SourceGenerators.Diagnostics;
internal static class AutoRegisterModuleDiagnostics
{

View File

@ -1,4 +1,4 @@
namespace GFramework.SourceGenerators.Diagnostics;
namespace GFramework.Core.SourceGenerators.Diagnostics;
/// <summary>
/// 提供与上下文感知相关的诊断规则定义

View File

@ -1,6 +1,6 @@
using GFramework.SourceGenerators.Common.Constants;
namespace GFramework.SourceGenerators.Diagnostics;
namespace GFramework.Core.SourceGenerators.Diagnostics;
/// <summary>
/// 提供 Context Get 注入生成器相关诊断。

View File

@ -1,6 +1,6 @@
using GFramework.SourceGenerators.Common.Constants;
namespace GFramework.SourceGenerators.Diagnostics;
namespace GFramework.Core.SourceGenerators.Diagnostics;
/// <summary>
/// 提供 Context Get 注册可见性分析相关诊断。

View File

@ -1,4 +1,4 @@
namespace GFramework.SourceGenerators.Diagnostics;
namespace GFramework.Core.SourceGenerators.Diagnostics;
/// <summary>
/// 提供诊断描述符的静态类用于GFramework日志生成器的编译时检查

View File

@ -1,4 +1,4 @@
namespace GFramework.SourceGenerators.Diagnostics;
namespace GFramework.Core.SourceGenerators.Diagnostics;
/// <summary>
/// Priority 特性相关的诊断信息

View File

@ -2,7 +2,7 @@
using GFramework.SourceGenerators.Common.Diagnostics;
using GFramework.SourceGenerators.Common.Generator;
namespace GFramework.SourceGenerators.Enums;
namespace GFramework.Core.SourceGenerators.Enums;
/// <summary>
/// 枚举扩展方法生成器,用于自动生成枚举相关的扩展方法

View File

@ -1,9 +1,9 @@
using GFramework.SourceGenerators.Abstractions.Logging;
using GFramework.Core.SourceGenerators.Abstractions.Logging;
using GFramework.SourceGenerators.Common.Constants;
using GFramework.SourceGenerators.Common.Extensions;
using GFramework.SourceGenerators.Common.Generator;
namespace GFramework.SourceGenerators.Logging;
namespace GFramework.Core.SourceGenerators.Logging;
/// <summary>
/// 日志生成器用于为标记了LogAttribute的类自动生成日志字段

View File

@ -1,9 +1,9 @@
using GFramework.SourceGenerators.Common.Constants;
using GFramework.Core.SourceGenerators.Diagnostics;
using GFramework.SourceGenerators.Common.Constants;
using GFramework.SourceGenerators.Common.Diagnostics;
using GFramework.SourceGenerators.Common.Generator;
using GFramework.SourceGenerators.Diagnostics;
namespace GFramework.SourceGenerators.Rule;
namespace GFramework.Core.SourceGenerators.Rule;
/// <summary>
/// 上下文感知生成器用于为标记了ContextAware特性的类自动生成IContextAware接口实现

View File

@ -1,10 +1,10 @@
using GFramework.Core.SourceGenerators.Diagnostics;
using GFramework.SourceGenerators.Common.Constants;
using GFramework.SourceGenerators.Common.Diagnostics;
using GFramework.SourceGenerators.Common.Extensions;
using GFramework.SourceGenerators.Common.Info;
using GFramework.SourceGenerators.Diagnostics;
namespace GFramework.SourceGenerators.Rule;
namespace GFramework.Core.SourceGenerators.Rule;
/// <summary>
/// 为上下文感知类生成 Core 上下文 Get 注入方法。

View File

@ -1,6 +1,6 @@
using GFramework.SourceGenerators.Common.Constants;
namespace GFramework.SourceGenerators.Cqrs;
namespace GFramework.Cqrs.SourceGenerators.Cqrs;
/// <summary>
/// 为当前编译程序集生成 CQRS 处理器注册器,以减少运行时的程序集反射扫描成本。
@ -347,7 +347,7 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
}
runtimeTypeReference = RuntimeTypeReferenceSpec.FromExternalReflectionLookup(
namedType.ContainingAssembly.Identity.Name,
namedType.ContainingAssembly.Identity.ToString(),
GetReflectionTypeMetadataName(namedType));
return true;
}
@ -396,7 +396,7 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
}
genericTypeDefinitionReference = RuntimeTypeReferenceSpec.FromExternalReflectionLookup(
genericTypeDefinition.ContainingAssembly.Identity.Name,
genericTypeDefinition.ContainingAssembly.Identity.ToString(),
GetReflectionTypeMetadataName(genericTypeDefinition));
return true;
}
@ -951,28 +951,39 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
if (includeExternalAssemblyTypeLookupHelpers)
{
builder.AppendLine(
" private static global::System.Type? ResolveReferencedAssemblyType(string assemblyName, string typeMetadataName)");
" private static global::System.Type? ResolveReferencedAssemblyType(string assemblyIdentity, string typeMetadataName)");
builder.AppendLine(" {");
builder.AppendLine(" var assembly = ResolveReferencedAssembly(assemblyName);");
builder.AppendLine(" var assembly = ResolveReferencedAssembly(assemblyIdentity);");
builder.AppendLine(
" return assembly?.GetType(typeMetadataName, throwOnError: false, ignoreCase: false);");
builder.AppendLine(" }");
builder.AppendLine();
builder.AppendLine(
" private static global::System.Reflection.Assembly? ResolveReferencedAssembly(string assemblyName)");
" private static global::System.Reflection.Assembly? ResolveReferencedAssembly(string assemblyIdentity)");
builder.AppendLine(" {");
builder.AppendLine(" global::System.Reflection.AssemblyName targetAssemblyName;");
builder.AppendLine(" try");
builder.AppendLine(" {");
builder.AppendLine(
" targetAssemblyName = new global::System.Reflection.AssemblyName(assemblyIdentity);");
builder.AppendLine(" }");
builder.AppendLine(" catch");
builder.AppendLine(" {");
builder.AppendLine(" return null;");
builder.AppendLine(" }");
builder.AppendLine();
builder.AppendLine(
" foreach (var assembly in global::System.AppDomain.CurrentDomain.GetAssemblies())");
builder.AppendLine(" {");
builder.AppendLine(
" if (global::System.StringComparer.Ordinal.Equals(assembly.GetName().Name, assemblyName))");
" if (global::System.Reflection.AssemblyName.ReferenceMatchesDefinition(targetAssemblyName, assembly.GetName()))");
builder.AppendLine(" return assembly;");
builder.AppendLine(" }");
builder.AppendLine();
builder.AppendLine(" try");
builder.AppendLine(" {");
builder.AppendLine(
" return global::System.Reflection.Assembly.Load(new global::System.Reflection.AssemblyName(assemblyName));");
" return global::System.Reflection.Assembly.Load(targetAssemblyName);");
builder.AppendLine(" }");
builder.AppendLine(" catch");
builder.AppendLine(" {");

View File

@ -1,6 +1,6 @@
using GFramework.SourceGenerators.Diagnostics;
using GFramework.Game.SourceGenerators.Diagnostics;
namespace GFramework.SourceGenerators.Config;
namespace GFramework.Game.SourceGenerators.Config;
/// <summary>
/// 根据 AdditionalFiles 中的 JSON schema 生成配置类型和配置表包装。

View File

@ -1,6 +1,6 @@
using GFramework.SourceGenerators.Common.Constants;
namespace GFramework.SourceGenerators.Diagnostics;
namespace GFramework.Game.SourceGenerators.Diagnostics;
/// <summary>
/// 提供配置 schema 代码生成相关诊断。

View File

@ -7,6 +7,7 @@
<IncludeBuildOutput>false</IncludeBuildOutput>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>

View File

@ -1,4 +1,4 @@
using GFramework.SourceGenerators.Analyzers;
using GFramework.Core.SourceGenerators.Analyzers;
using GFramework.SourceGenerators.Tests.Core;
namespace GFramework.SourceGenerators.Tests.Analyzers;
@ -9,128 +9,128 @@ namespace GFramework.SourceGenerators.Tests.Analyzers;
public sealed class ContextRegistrationAnalyzerTests
{
private const string TestPreamble = """
using System;
using System.Collections.Generic;
namespace GFramework.Core.Abstractions.Rule
{
public interface IContextAware { }
}
namespace GFramework.Core.Abstractions.Model
{
public interface IModel : GFramework.Core.Abstractions.Rule.IContextAware { }
}
namespace GFramework.Core.Abstractions.Systems
{
public interface ISystem : GFramework.Core.Abstractions.Rule.IContextAware { }
}
namespace GFramework.Core.Abstractions.Utility
{
public interface IUtility : GFramework.Core.Abstractions.Rule.IContextAware { }
}
namespace GFramework.Core.Abstractions.Architectures
{
public interface IArchitecture
{
T RegisterModel<T>(T model) where T : GFramework.Core.Abstractions.Model.IModel;
void RegisterModel<T>(Action<T> onCreated = null) where T : class, GFramework.Core.Abstractions.Model.IModel;
T RegisterSystem<T>(T system) where T : GFramework.Core.Abstractions.Systems.ISystem;
void RegisterSystem<T>(Action<T> onCreated = null) where T : class, GFramework.Core.Abstractions.Systems.ISystem;
T RegisterUtility<T>(T utility) where T : GFramework.Core.Abstractions.Utility.IUtility;
void RegisterUtility<T>(Action<T> onCreated = null) where T : class, GFramework.Core.Abstractions.Utility.IUtility;
IArchitectureModule InstallModule(IArchitectureModule module);
}
public interface IArchitectureModule
{
void Install(IArchitecture architecture);
}
public interface IArchitectureContext
{
TModel GetModel<TModel>() where TModel : class, GFramework.Core.Abstractions.Model.IModel;
IReadOnlyList<TModel> GetModels<TModel>() where TModel : class, GFramework.Core.Abstractions.Model.IModel;
TSystem GetSystem<TSystem>() where TSystem : class, GFramework.Core.Abstractions.Systems.ISystem;
IReadOnlyList<TSystem> GetSystems<TSystem>() where TSystem : class, GFramework.Core.Abstractions.Systems.ISystem;
TUtility GetUtility<TUtility>() where TUtility : class, GFramework.Core.Abstractions.Utility.IUtility;
IReadOnlyList<TUtility> GetUtilities<TUtility>() where TUtility : class, GFramework.Core.Abstractions.Utility.IUtility;
}
}
namespace GFramework.Core.Architectures
{
public abstract class Architecture : GFramework.Core.Abstractions.Architectures.IArchitecture
{
protected abstract void OnInitialize();
public virtual T RegisterModel<T>(T model) where T : GFramework.Core.Abstractions.Model.IModel => model;
public virtual void RegisterModel<T>(Action<T> onCreated = null)
where T : class, GFramework.Core.Abstractions.Model.IModel
{
}
public virtual T RegisterSystem<T>(T system) where T : GFramework.Core.Abstractions.Systems.ISystem => system;
public virtual void RegisterSystem<T>(Action<T> onCreated = null)
where T : class, GFramework.Core.Abstractions.Systems.ISystem
{
}
public virtual T RegisterUtility<T>(T utility) where T : GFramework.Core.Abstractions.Utility.IUtility => utility;
public virtual void RegisterUtility<T>(Action<T> onCreated = null)
where T : class, GFramework.Core.Abstractions.Utility.IUtility
{
}
public virtual GFramework.Core.Abstractions.Architectures.IArchitectureModule InstallModule(
GFramework.Core.Abstractions.Architectures.IArchitectureModule module)
{
module.Install(this);
return module;
}
}
}
namespace GFramework.Core.Extensions
{
public static class ContextAwareServiceExtensions
{
public static TModel GetModel<TModel>(this GFramework.Core.Abstractions.Rule.IContextAware contextAware)
where TModel : class, GFramework.Core.Abstractions.Model.IModel => throw new NotImplementedException();
public static IReadOnlyList<TModel> GetModels<TModel>(this GFramework.Core.Abstractions.Rule.IContextAware contextAware)
where TModel : class, GFramework.Core.Abstractions.Model.IModel => throw new NotImplementedException();
public static TSystem GetSystem<TSystem>(this GFramework.Core.Abstractions.Rule.IContextAware contextAware)
where TSystem : class, GFramework.Core.Abstractions.Systems.ISystem => throw new NotImplementedException();
public static IReadOnlyList<TSystem> GetSystems<TSystem>(this GFramework.Core.Abstractions.Rule.IContextAware contextAware)
where TSystem : class, GFramework.Core.Abstractions.Systems.ISystem => throw new NotImplementedException();
public static TUtility GetUtility<TUtility>(this GFramework.Core.Abstractions.Rule.IContextAware contextAware)
where TUtility : class, GFramework.Core.Abstractions.Utility.IUtility => throw new NotImplementedException();
public static IReadOnlyList<TUtility> GetUtilities<TUtility>(this GFramework.Core.Abstractions.Rule.IContextAware contextAware)
where TUtility : class, GFramework.Core.Abstractions.Utility.IUtility => throw new NotImplementedException();
}
}
namespace GFramework.SourceGenerators.Abstractions.Rule
{
public sealed class GetModelAttribute : Attribute { }
public sealed class GetModelsAttribute : Attribute { }
public sealed class GetSystemAttribute : Attribute { }
public sealed class GetSystemsAttribute : Attribute { }
public sealed class GetUtilityAttribute : Attribute { }
public sealed class GetUtilitiesAttribute : Attribute { }
}
""";
using System;
using System.Collections.Generic;
namespace GFramework.Core.Abstractions.Rule
{
public interface IContextAware { }
}
namespace GFramework.Core.Abstractions.Model
{
public interface IModel : GFramework.Core.Abstractions.Rule.IContextAware { }
}
namespace GFramework.Core.Abstractions.Systems
{
public interface ISystem : GFramework.Core.Abstractions.Rule.IContextAware { }
}
namespace GFramework.Core.Abstractions.Utility
{
public interface IUtility : GFramework.Core.Abstractions.Rule.IContextAware { }
}
namespace GFramework.Core.Abstractions.Architectures
{
public interface IArchitecture
{
T RegisterModel<T>(T model) where T : GFramework.Core.Abstractions.Model.IModel;
void RegisterModel<T>(Action<T> onCreated = null) where T : class, GFramework.Core.Abstractions.Model.IModel;
T RegisterSystem<T>(T system) where T : GFramework.Core.Abstractions.Systems.ISystem;
void RegisterSystem<T>(Action<T> onCreated = null) where T : class, GFramework.Core.Abstractions.Systems.ISystem;
T RegisterUtility<T>(T utility) where T : GFramework.Core.Abstractions.Utility.IUtility;
void RegisterUtility<T>(Action<T> onCreated = null) where T : class, GFramework.Core.Abstractions.Utility.IUtility;
IArchitectureModule InstallModule(IArchitectureModule module);
}
public interface IArchitectureModule
{
void Install(IArchitecture architecture);
}
public interface IArchitectureContext
{
TModel GetModel<TModel>() where TModel : class, GFramework.Core.Abstractions.Model.IModel;
IReadOnlyList<TModel> GetModels<TModel>() where TModel : class, GFramework.Core.Abstractions.Model.IModel;
TSystem GetSystem<TSystem>() where TSystem : class, GFramework.Core.Abstractions.Systems.ISystem;
IReadOnlyList<TSystem> GetSystems<TSystem>() where TSystem : class, GFramework.Core.Abstractions.Systems.ISystem;
TUtility GetUtility<TUtility>() where TUtility : class, GFramework.Core.Abstractions.Utility.IUtility;
IReadOnlyList<TUtility> GetUtilities<TUtility>() where TUtility : class, GFramework.Core.Abstractions.Utility.IUtility;
}
}
namespace GFramework.Core.Architectures
{
public abstract class Architecture : GFramework.Core.Abstractions.Architectures.IArchitecture
{
protected abstract void OnInitialize();
public virtual T RegisterModel<T>(T model) where T : GFramework.Core.Abstractions.Model.IModel => model;
public virtual void RegisterModel<T>(Action<T> onCreated = null)
where T : class, GFramework.Core.Abstractions.Model.IModel
{
}
public virtual T RegisterSystem<T>(T system) where T : GFramework.Core.Abstractions.Systems.ISystem => system;
public virtual void RegisterSystem<T>(Action<T> onCreated = null)
where T : class, GFramework.Core.Abstractions.Systems.ISystem
{
}
public virtual T RegisterUtility<T>(T utility) where T : GFramework.Core.Abstractions.Utility.IUtility => utility;
public virtual void RegisterUtility<T>(Action<T> onCreated = null)
where T : class, GFramework.Core.Abstractions.Utility.IUtility
{
}
public virtual GFramework.Core.Abstractions.Architectures.IArchitectureModule InstallModule(
GFramework.Core.Abstractions.Architectures.IArchitectureModule module)
{
module.Install(this);
return module;
}
}
}
namespace GFramework.Core.Extensions
{
public static class ContextAwareServiceExtensions
{
public static TModel GetModel<TModel>(this GFramework.Core.Abstractions.Rule.IContextAware contextAware)
where TModel : class, GFramework.Core.Abstractions.Model.IModel => throw new NotImplementedException();
public static IReadOnlyList<TModel> GetModels<TModel>(this GFramework.Core.Abstractions.Rule.IContextAware contextAware)
where TModel : class, GFramework.Core.Abstractions.Model.IModel => throw new NotImplementedException();
public static TSystem GetSystem<TSystem>(this GFramework.Core.Abstractions.Rule.IContextAware contextAware)
where TSystem : class, GFramework.Core.Abstractions.Systems.ISystem => throw new NotImplementedException();
public static IReadOnlyList<TSystem> GetSystems<TSystem>(this GFramework.Core.Abstractions.Rule.IContextAware contextAware)
where TSystem : class, GFramework.Core.Abstractions.Systems.ISystem => throw new NotImplementedException();
public static TUtility GetUtility<TUtility>(this GFramework.Core.Abstractions.Rule.IContextAware contextAware)
where TUtility : class, GFramework.Core.Abstractions.Utility.IUtility => throw new NotImplementedException();
public static IReadOnlyList<TUtility> GetUtilities<TUtility>(this GFramework.Core.Abstractions.Rule.IContextAware contextAware)
where TUtility : class, GFramework.Core.Abstractions.Utility.IUtility => throw new NotImplementedException();
}
}
namespace GFramework.SourceGenerators.Abstractions.Rule
{
public sealed class GetModelAttribute : Attribute { }
public sealed class GetModelsAttribute : Attribute { }
public sealed class GetSystemAttribute : Attribute { }
public sealed class GetSystemsAttribute : Attribute { }
public sealed class GetUtilityAttribute : Attribute { }
public sealed class GetUtilitiesAttribute : Attribute { }
}
""";
[Test]
public async Task Reports_Warning_When_FieldInjectedModel_Is_Not_Registered()
@ -366,7 +366,8 @@ public sealed class ContextRegistrationAnalyzerTests
}
[Test]
public async Task Does_Not_Report_When_Inherited_OnInitialize_Calls_Virtual_Helper_Overridden_In_Derived_Architecture()
public async Task
Does_Not_Report_When_Inherited_OnInitialize_Calls_Virtual_Helper_Overridden_In_Derived_Architecture()
{
await AnalyzerTestDriver<ContextRegistrationAnalyzer>.RunAsync(
Wrap("""

View File

@ -1,4 +1,4 @@
using GFramework.SourceGenerators.Architectures;
using GFramework.Core.SourceGenerators.Architectures;
using GFramework.SourceGenerators.Tests.Core;
namespace GFramework.SourceGenerators.Tests.Architectures;
@ -180,42 +180,42 @@ public class AutoRegisterModuleGeneratorTests
""";
const string partASource = """
namespace TestApp
{
using GFramework.SourceGenerators.Abstractions.Architectures;
namespace TestApp
{
using GFramework.SourceGenerators.Abstractions.Architectures;
// Padding ensures this attribute lives later in the file than the attributes in PartB.
// The generator should still place it first because PartA sorts before PartB.
// padding 01
// padding 02
// padding 03
// padding 04
// padding 05
// padding 06
// padding 07
// padding 08
// padding 09
// padding 10
[AutoRegisterModule]
[RegisterUtility(typeof(AudioUtility))]
public partial class GameplayModule
{
}
}
""";
// Padding ensures this attribute lives later in the file than the attributes in PartB.
// The generator should still place it first because PartA sorts before PartB.
// padding 01
// padding 02
// padding 03
// padding 04
// padding 05
// padding 06
// padding 07
// padding 08
// padding 09
// padding 10
[AutoRegisterModule]
[RegisterUtility(typeof(AudioUtility))]
public partial class GameplayModule
{
}
}
""";
const string partBSource = """
namespace TestApp
{
using GFramework.SourceGenerators.Abstractions.Architectures;
namespace TestApp
{
using GFramework.SourceGenerators.Abstractions.Architectures;
[RegisterSystem(typeof(CombatSystem))]
[RegisterModel(typeof(PlayerModel))]
public partial class GameplayModule
{
}
}
""";
[RegisterSystem(typeof(CombatSystem))]
[RegisterModel(typeof(PlayerModel))]
public partial class GameplayModule
{
}
}
""";
const string expected = """
// <auto-generated />
@ -247,7 +247,8 @@ public class AutoRegisterModuleGeneratorTests
},
GeneratedSources =
{
(typeof(AutoRegisterModuleGenerator), "TestApp_GameplayModule.AutoRegisterModule.g.cs", NormalizeLineEndings(expected))
(typeof(AutoRegisterModuleGenerator), "TestApp_GameplayModule.AutoRegisterModule.g.cs",
NormalizeLineEndings(expected))
}
},
DisabledDiagnostics = { "GF_Common_Trace_001" }

View File

@ -1,7 +1,6 @@
using System.IO;
using GFramework.SourceGenerators.Bases;
using GFramework.Core.SourceGenerators.Bases;
using GFramework.SourceGenerators.Tests.Core;
using NUnit.Framework;
namespace GFramework.SourceGenerators.Tests.Bases;
@ -212,4 +211,4 @@ public class PriorityGeneratorSnapshotTests
"PriorityGenerator",
"GenericClass"));
}
}
}

View File

@ -1,7 +1,6 @@
using System.Collections.Immutable;
using System.IO;
using GFramework.SourceGenerators.Config;
using Microsoft.CodeAnalysis.CSharp;
using GFramework.Game.SourceGenerators.Config;
namespace GFramework.SourceGenerators.Tests.Config;
@ -85,4 +84,4 @@ public static class SchemaGeneratorTestDriver
return _text;
}
}
}
}

View File

@ -1,5 +1,5 @@
using System.Reflection;
using GFramework.SourceGenerators.Cqrs;
using GFramework.Cqrs.SourceGenerators.Cqrs;
using GFramework.SourceGenerators.Tests.Core;
namespace GFramework.SourceGenerators.Tests.Cqrs;
@ -252,6 +252,84 @@ public class CqrsHandlerRegistryGeneratorTests
""";
private const string ExternalAssemblyPreciseLookupExpected = """
// <auto-generated />
#nullable enable
[assembly: global::GFramework.Cqrs.CqrsHandlerRegistryAttribute(typeof(global::GFramework.Generated.Cqrs.__GFrameworkGeneratedCqrsHandlerRegistry))]
namespace GFramework.Generated.Cqrs;
internal sealed class __GFrameworkGeneratedCqrsHandlerRegistry : global::GFramework.Cqrs.ICqrsHandlerRegistry
{
public void Register(global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, global::GFramework.Core.Abstractions.Logging.ILogger logger)
{
if (services is null)
throw new global::System.ArgumentNullException(nameof(services));
if (logger is null)
throw new global::System.ArgumentNullException(nameof(logger));
var registryAssembly = typeof(global::GFramework.Generated.Cqrs.__GFrameworkGeneratedCqrsHandlerRegistry).Assembly;
var implementationType0 = typeof(global::TestApp.DerivedHandler);
if (implementationType0 is not null)
{
var serviceType0_0Argument0 = ResolveReferencedAssemblyType("Dependency, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "Dep.VisibilityScope+ProtectedRequest");
var serviceType0_0Argument1Element = ResolveReferencedAssemblyType("Dependency, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "Dep.VisibilityScope+ProtectedResponse");
if (serviceType0_0Argument0 is not null && serviceType0_0Argument1Element is not null)
{
var serviceType0_0 = typeof(global::GFramework.Cqrs.Abstractions.Cqrs.IRequestHandler<,>).MakeGenericType(serviceType0_0Argument0, serviceType0_0Argument1Element.MakeArrayType());
global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddTransient(
services,
serviceType0_0,
implementationType0);
logger.Debug("Registered CQRS handler TestApp.DerivedHandler as GFramework.Cqrs.Abstractions.Cqrs.IRequestHandler<Dep.VisibilityScope.ProtectedRequest, Dep.VisibilityScope.ProtectedResponse[]>.");
}
global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddTransient(
services,
typeof(global::GFramework.Cqrs.Abstractions.Cqrs.IRequestHandler<global::Dep.VisibleRequest, string>),
implementationType0);
logger.Debug("Registered CQRS handler TestApp.DerivedHandler as GFramework.Cqrs.Abstractions.Cqrs.IRequestHandler<Dep.VisibleRequest, string>.");
}
}
private static global::System.Type? ResolveReferencedAssemblyType(string assemblyIdentity, string typeMetadataName)
{
var assembly = ResolveReferencedAssembly(assemblyIdentity);
return assembly?.GetType(typeMetadataName, throwOnError: false, ignoreCase: false);
}
private static global::System.Reflection.Assembly? ResolveReferencedAssembly(string assemblyIdentity)
{
global::System.Reflection.AssemblyName targetAssemblyName;
try
{
targetAssemblyName = new global::System.Reflection.AssemblyName(assemblyIdentity);
}
catch
{
return null;
}
foreach (var assembly in global::System.AppDomain.CurrentDomain.GetAssemblies())
{
if (global::System.Reflection.AssemblyName.ReferenceMatchesDefinition(targetAssemblyName, assembly.GetName()))
return assembly;
}
try
{
return global::System.Reflection.Assembly.Load(targetAssemblyName);
}
catch
{
return null;
}
}
}
""";
/// <summary>
/// 验证生成器会为当前程序集中的 request、notification 和 stream 处理器生成稳定顺序的注册器。
/// </summary>
@ -923,37 +1001,9 @@ public class CqrsHandlerRegistryGeneratorTests
contractsReference,
dependencyReference);
Assert.Multiple(() =>
{
Assert.That(
generatedSource,
Does.Contain("var implementationType0 = typeof(global::TestApp.DerivedHandler);"));
Assert.That(
generatedSource,
Does.Contain(
"ResolveReferencedAssemblyType(\"Dependency\", \"Dep.VisibilityScope+ProtectedRequest\")"));
Assert.That(
generatedSource,
Does.Contain(
"ResolveReferencedAssemblyType(\"Dependency\", \"Dep.VisibilityScope+ProtectedResponse\")"));
Assert.That(
generatedSource,
Does.Contain(
"typeof(global::GFramework.Cqrs.Abstractions.Cqrs.IRequestHandler<global::Dep.VisibleRequest, string>)"));
Assert.That(
generatedSource,
Does.Contain("ResolveReferencedAssembly(string assemblyName)"));
Assert.That(
generatedSource,
Does.Not.Contain("knownServiceTypes0"));
Assert.That(
generatedSource,
Does.Not.Contain("RegisterRemainingReflectedHandlerInterfaces"));
Assert.That(
generatedSource,
Does.Not.Contain(
"// Remaining runtime interface discovery target:"));
});
Assert.That(
generatedSource,
Is.EqualTo(ExternalAssemblyPreciseLookupExpected));
}
/// <summary>

View File

@ -1,7 +1,6 @@
using System.IO;
using GFramework.SourceGenerators.Enums;
using GFramework.Core.SourceGenerators.Enums;
using GFramework.SourceGenerators.Tests.Core;
using NUnit.Framework;
namespace GFramework.SourceGenerators.Tests.Enums;
@ -206,4 +205,4 @@ public class EnumExtensionsGeneratorSnapshotTests
"EnumExtensionsGenerator",
"DisableIsInMethod"));
}
}
}

View File

@ -1,7 +1,6 @@
using System.IO;
using GFramework.SourceGenerators.Logging;
using GFramework.Core.SourceGenerators.Logging;
using GFramework.SourceGenerators.Tests.Core;
using NUnit.Framework;
namespace GFramework.SourceGenerators.Tests.Logging;
@ -589,4 +588,4 @@ public class LoggerGeneratorSnapshotTests
"LoggerGenerator",
"GenericClass"));
}
}
}

View File

@ -1,7 +1,6 @@
using System.IO;
using GFramework.SourceGenerators.Rule;
using GFramework.Core.SourceGenerators.Rule;
using GFramework.SourceGenerators.Tests.Core;
using NUnit.Framework;
namespace GFramework.SourceGenerators.Tests.Rule;
@ -93,4 +92,4 @@ public class ContextAwareGeneratorSnapshotTests
"snapshots",
"ContextAwareGenerator"));
}
}
}

View File

@ -1,4 +1,4 @@
using GFramework.SourceGenerators.Rule;
using GFramework.Core.SourceGenerators.Rule;
using GFramework.SourceGenerators.Tests.Core;
namespace GFramework.SourceGenerators.Tests.Rule;

View File

@ -30,19 +30,18 @@
<None Remove="GFramework.Game\**"/>
<None Remove="GFramework.Godot\**"/>
<None Update="GFramework.Core.SourceGenerators\logging\README.md">
<Link>GFramework.SorceGenerators\logging\README.md</Link>
<Link>GFramework.Core.SourceGenerators\logging\README.md</Link>
</None>
<None Update="GFramework.Core.SourceGenerators\README.md">
<Link>GFramework.SorceGenerators\README.md</Link>
<Link>GFramework.Core.SourceGenerators\README.md</Link>
</None>
<None Update="GFramework.Core.SourceGenerators\AnalyzerReleases.Shipped.md">
<Link>GFramework.SorceGenerators\AnalyzerReleases.Shipped.md</Link>
<Link>GFramework.Core.SourceGenerators\AnalyzerReleases.Shipped.md</Link>
</None>
<None Update="GFramework.Core.SourceGenerators\AnalyzerReleases.Unshipped.md">
<Link>GFramework.SorceGenerators\AnalyzerReleases.Unshipped.md</Link>
<Link>GFramework.Core.SourceGenerators\AnalyzerReleases.Unshipped.md</Link>
</None>
<None Remove="GFramework.Godot.SourceGenerators\**"/>
<None Remove="GFramework.SorceGenerators\**"/>
<None Remove="GFramework.SourceGenerators\**"/>
<None Remove="GFramework.Core.SourceGenerators\**"/>
<None Remove="GFramework.Core.SourceGenerators.Abstractions\**"/>
@ -82,16 +81,15 @@
<Compile Remove="GFramework.Game\**"/>
<Compile Remove="GFramework.Godot\**"/>
<Compile Update="GFramework.Core.SourceGenerators\enums\EnumExtensionsGenerator.cs">
<Link>GFramework.SorceGenerators\enums\EnumExtensionsGenerator.cs</Link>
<Link>GFramework.Core.SourceGenerators\enums\EnumExtensionsGenerator.cs</Link>
</Compile>
<Compile Update="GFramework.Core.SourceGenerators\logging\Diagnostic.cs">
<Link>GFramework.SorceGenerators\logging\Diagnostic.cs</Link>
<Link>GFramework.Core.SourceGenerators\logging\Diagnostic.cs</Link>
</Compile>
<Compile Update="GFramework.Core.SourceGenerators\logging\LoggerGenerator.cs">
<Link>GFramework.SorceGenerators\logging\LoggerGenerator.cs</Link>
<Link>GFramework.Core.SourceGenerators\logging\LoggerGenerator.cs</Link>
</Compile>
<Compile Remove="GFramework.Godot.SourceGenerators\**"/>
<Compile Remove="GFramework.SorceGenerators\**"/>
<Compile Remove="GFramework.SourceGenerators\**"/>
<Compile Remove="GFramework.Core.SourceGenerators\**"/>
<Compile Remove="GFramework.Core.SourceGenerators.Abstractions\**"/>
@ -126,7 +124,6 @@
<EmbeddedResource Remove="GFramework.Game\**"/>
<EmbeddedResource Remove="GFramework.Godot\**"/>
<EmbeddedResource Remove="GFramework.Godot.SourceGenerators\**"/>
<EmbeddedResource Remove="GFramework.SorceGenerators\**"/>
<EmbeddedResource Remove="GFramework.SourceGenerators\**"/>
<EmbeddedResource Remove="GFramework.Core.SourceGenerators\**"/>
<EmbeddedResource Remove="GFramework.Core.SourceGenerators.Abstractions\**"/>

View File

@ -68,8 +68,11 @@ dotnet add package GeWuYou.GFramework.Game.Abstractions
# Godot 集成(仅 Godot 项目需要)
dotnet add package GeWuYou.GFramework.Godot
# 源码生成器(可选,但推荐)
dotnet add package GeWuYou.GFramework.SourceGenerators
# 按场景选择源码生成器(可选,但推荐)
dotnet add package GeWuYou.GFramework.Core.SourceGenerators
dotnet add package GeWuYou.GFramework.Game.SourceGenerators
dotnet add package GeWuYou.GFramework.Godot.SourceGenerators
dotnet add package GeWuYou.GFramework.Cqrs.SourceGenerators
```
## 可选模块导入

View File

@ -247,6 +247,8 @@ public class GameArchitecture : Architecture
handler。
`RegisterCqrsPipelineBehavior<TBehavior>()` 是唯一保留的公开入口;旧的 `Mediator` 兼容别名与扩展已移除,不再继续维护。
如果你正在从旧版本迁移,显式替换关系就是
`RegisterMediatorBehavior<TBehavior>() -> RegisterCqrsPipelineBehavior<TBehavior>()`
当前接口支持两种形式:
- 开放泛型行为,例如 `LoggingBehavior<,>`,用于匹配所有请求

View File

@ -180,7 +180,9 @@ GameProject/
如果你使用打包后的 NuGet而不是仓库内项目引用原则保持不变
- 运行时项目需要引用 `GeWuYou.GFramework.Game`
- 生成器项目需要引用 `GeWuYou.GFramework.SourceGenerators`
- 配置 schema 生成器需要引用 `GeWuYou.GFramework.Game.SourceGenerators`
- 如果同一项目还会使用 `[Log]``[ContextAware]``[GetSystem]` 等 Core 侧生成器特性,再额外引用
`GeWuYou.GFramework.Core.SourceGenerators`
- schema 目录默认仍然是 `schemas/`
如果你的 schema 不放在默认目录,可以在项目文件里覆盖:

View File

@ -6,13 +6,18 @@ GFramework 提供多种安装方式,您可以根据项目需求选择合适的
GFramework 采用模块化设计,不同包提供不同的功能:
| 包名 | 说明 | 适用场景 |
|---------------------------------------|---------|-----------|
| `GeWuYou.GFramework` | 聚合元包 | 快速试用、原型开发 |
| `GeWuYou.GFramework.Core` | 核心框架 | 生产项目推荐 |
| `GeWuYou.GFramework.Game` | 游戏模块 | 需要游戏特定功能 |
| `GeWuYou.GFramework.Godot` | Godot集成 | Godot项目必需 |
| `GeWuYou.GFramework.SourceGenerators` | 源码生成器 | 推荐安装 |
| 包名 | 说明 | 适用场景 |
|---------------------------------------------|-------------|--------------------------------|
| `GeWuYou.GFramework` | 聚合元包 | 快速试用、原型开发 |
| `GeWuYou.GFramework.Core` | 核心框架 | 生产项目推荐 |
| `GeWuYou.GFramework.Game` | 游戏模块 | 需要游戏特定功能 |
| `GeWuYou.GFramework.Godot` | Godot集成 | Godot项目必需 |
| `GeWuYou.GFramework.Core.SourceGenerators` | Core 源码生成器 | `[Log]``[ContextAware]`、架构注入等 |
| `GeWuYou.GFramework.Game.SourceGenerators` | Game 源码生成器 | 配置 schema / 配表生成 |
| `GeWuYou.GFramework.Godot.SourceGenerators` | Godot 源码生成器 | Godot 节点、UI、项目元数据生成 |
| `GeWuYou.GFramework.Cqrs.SourceGenerators` | CQRS 源码生成器 | 处理器注册表生成 |
当前 NuGet 发布按模块拆分 source generator 包,不存在 `GeWuYou.GFramework.SourceGenerators` 聚合包。
## 安装方式
@ -30,8 +35,17 @@ dotnet add package GeWuYou.GFramework.Game.Abstractions
# Godot 集成(仅 Godot 项目需要)
dotnet add package GeWuYou.GFramework.Godot
# 源码生成器(可选,但推荐)
dotnet add package GeWuYou.GFramework.SourceGenerators
# Core 侧源码生成器([Log] / [ContextAware] / [GetSystem] 等)
dotnet add package GeWuYou.GFramework.Core.SourceGenerators
# Game 配置 schema 生成器
dotnet add package GeWuYou.GFramework.Game.SourceGenerators
# Godot 生成器(仅 Godot 项目需要)
dotnet add package GeWuYou.GFramework.Godot.SourceGenerators
# CQRS 处理器注册生成器(仅使用 CQRS source generator 时需要)
dotnet add package GeWuYou.GFramework.Cqrs.SourceGenerators
```
### 2. 使用 PackageReference
@ -56,8 +70,14 @@ dotnet add package GeWuYou.GFramework.SourceGenerators
<!-- Godot 集成 -->
<PackageReference Include="GeWuYou.GFramework.Godot" Version="1.0.0" />
<!-- 源码生成器 -->
<PackageReference Include="GeWuYou.GFramework.SourceGenerators" Version="1.0.0"
<!-- 按场景选择的源码生成器 -->
<PackageReference Include="GeWuYou.GFramework.Core.SourceGenerators" Version="1.0.0"
PrivateAssets="all" ExcludeAssets="runtime" />
<PackageReference Include="GeWuYou.GFramework.Game.SourceGenerators" Version="1.0.0"
PrivateAssets="all" ExcludeAssets="runtime" />
<PackageReference Include="GeWuYou.GFramework.Godot.SourceGenerators" Version="1.0.0"
PrivateAssets="all" ExcludeAssets="runtime" />
<PackageReference Include="GeWuYou.GFramework.Cqrs.SourceGenerators" Version="1.0.0"
PrivateAssets="all" ExcludeAssets="runtime" />
</ItemGroup>
</Project>
@ -183,6 +203,8 @@ dotnet build
检查:
- 确保安装了 `GeWuYou.GFramework.SourceGenerators`
- 确保安装了与你正在使用的特性对应的拆分生成器包,例如:
`GeWuYou.GFramework.Core.SourceGenerators``GeWuYou.GFramework.Game.SourceGenerators`
`GeWuYou.GFramework.Godot.SourceGenerators``GeWuYou.GFramework.Cqrs.SourceGenerators`
- 重启 IDE
- 清理并重新构建项目

View File

@ -30,7 +30,16 @@ GFramework.SourceGenerators 是 GFramework 框架的源代码生成器包,通
## 概述
GFramework.SourceGenerators 利用 Roslyn 源代码生成器技术,在编译时分析你的代码并自动生成常用的样板代码,让开发者专注于业务逻辑而不是重复的模板代码。
GFramework 的 source generators 利用 Roslyn 源代码生成器技术,在编译时分析你的代码并自动生成常用的样板代码,让开发者专注于业务逻辑而不是重复的模板代码。
当前 NuGet 发布按模块拆分为:
- `GeWuYou.GFramework.Core.SourceGenerators`
- `GeWuYou.GFramework.Game.SourceGenerators`
- `GeWuYou.GFramework.Godot.SourceGenerators`
- `GeWuYou.GFramework.Cqrs.SourceGenerators`
不存在 `GeWuYou.GFramework.SourceGenerators``GeWuYou.GFramework.SourceGenerators.Attributes` 这类聚合包。
### 核心设计理念
@ -74,22 +83,30 @@ GFramework.SourceGenerators 利用 Roslyn 源代码生成器技术,在编译
### NuGet 包安装
```xml
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="GeWuYou.GFramework.SourceGenerators" Version="1.0.0"/>
<PackageReference Include="GeWuYou.GFramework.SourceGenerators.Attributes" Version="1.0.0"/>
<PackageReference Include="GeWuYou.GFramework.Core.SourceGenerators" Version="1.0.0"
PrivateAssets="all"
ExcludeAssets="runtime" />
<PackageReference Include="GeWuYou.GFramework.Game.SourceGenerators" Version="1.0.0"
PrivateAssets="all"
ExcludeAssets="runtime" />
</ItemGroup>
</Project>
```
如果你只使用 Godot 生成器或 CQRS 处理器注册生成器,请把上面的包替换为对应的
`GeWuYou.GFramework.Godot.SourceGenerators``GeWuYou.GFramework.Cqrs.SourceGenerators`
这些拆分包会同时带上各自需要的 abstractions 程序集,不需要再额外安装单独的 `*.Attributes` 包。
### Config Schema 文件约定
当项目引用 `GeWuYou.GFramework.SourceGenerators` 的打包产物时,生成器会默认从 `schemas/**/*.schema.json` 收集配置 schema
当项目引用 `GeWuYou.GFramework.Game.SourceGenerators` 的打包产物时,生成器会默认从 `schemas/**/*.schema.json` 收集配置
schema
文件并作为 `AdditionalFiles` 输入。
这意味着消费者项目通常只需要维护如下结构:
@ -150,7 +167,7 @@ Config Schema 生成器会扫描 `*.schema.json` 文件,并生成:
### 基础使用
```csharp
using GFramework.SourceGenerators.Attributes;
using GFramework.SourceGenerators.Abstractions.Logging;
[Log]
public partial class PlayerController

View File

@ -74,8 +74,11 @@ dotnet add package GeWuYou.GFramework
# Godot 集成
dotnet add package GeWuYou.GFramework.Godot
# 源码生成器(可选,但推荐)
dotnet add package GeWuYou.GFramework.SourceGenerators
# Core 侧源码生成器([Log] / [ContextAware] 等)
dotnet add package GeWuYou.GFramework.Core.SourceGenerators
# Godot 侧源码生成器([GetNode] / [AutoUiPage] 等)
dotnet add package GeWuYou.GFramework.Godot.SourceGenerators
```
::: details 分包安装(了解即可)
@ -93,8 +96,11 @@ dotnet add package GeWuYou.GFramework.Game.Abstractions
# Godot 集成
dotnet add package GeWuYou.GFramework.Godot
# 源码生成器
dotnet add package GeWuYou.GFramework.SourceGenerators
# Core 侧源码生成器
dotnet add package GeWuYou.GFramework.Core.SourceGenerators
# Godot 侧源码生成器
dotnet add package GeWuYou.GFramework.Godot.SourceGenerators
```
:::
@ -108,7 +114,8 @@ dotnet add package GeWuYou.GFramework.SourceGenerators
3. 安装以下包:
- `GeWuYou.GFramework`
- `GeWuYou.GFramework.Godot`
- `GeWuYou.GFramework.SourceGenerators`
- `GeWuYou.GFramework.Core.SourceGenerators`
- `GeWuYou.GFramework.Godot.SourceGenerators`
![NuGet 包管理](../assets/basic/image-20260211211756993.png)