using Fantasy.SourceGenerator.Common; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Collections.Generic; using System.Linq; using System.Text; // ReSharper disable MemberHidesStaticFromOuterClass namespace Fantasy.SourceGenerator.Generators { /// /// SeparateTable 接口生成器 /// 自动生成 SeparateTable 所需的注册代码,替代运行时反射 /// [Generator] public partial class SeparateTableGenerator : IIncrementalGenerator { private static readonly SourceCodeBuilder SeparateTableInfo = new SourceCodeBuilder(); public void Initialize(IncrementalGeneratorInitializationContext context) { // 查找所有标记了 SeparateTableAttribute 的类 var attributedClasses = context.SyntaxProvider .CreateSyntaxProvider( predicate: static (node, _) => IsSeparateTableClass(node), transform: static (ctx, _) => GetSeparateTableTypeInfo(ctx)) .Where(static info => info != null) .Collect(); // 组合编译信息和找到的类型 var compilationAndTypes = context.CompilationProvider.Combine(attributedClasses); // 注册源代码输出 context.RegisterSourceOutput(compilationAndTypes, static (spc, source) => { // 检查1: 是否定义了 FANTASY_NET 预编译符号 if (!CompilationHelper.HasFantasyNETDefine(source.Left)) { return; } // 检查2: 是否引用了 Fantasy 框架的核心类型 if (source.Left.GetTypeByMetadataName("Fantasy.Entitas.Interface.ISupportedSeparateTable") == null) { return; } GenerateRegistrationCode(spc, source.Left, source.Right!); }); } private static SeparateTableTypeInfo? GetSeparateTableTypeInfo(GeneratorSyntaxContext context) { var classDecl = (ClassDeclarationSyntax)context.Node; if (context.SemanticModel.GetDeclaredSymbol(classDecl) is not INamedTypeSymbol symbol) { return null; } if (!symbol.InheritsFrom("Fantasy.Entitas.Entity")) { // 不是 Entity,不处理 return null; } // 检查是否标记了 SeparateTableAttribute var separateTableAttr = symbol.GetAttributes() .Where(attr => attr.AttributeClass?.ToDisplayString() == "Fantasy.SeparateTable.SeparateTableAttribute").ToList(); if (!separateTableAttr.Any()) { return null; } var separateTableInfo = new Dictionary(); foreach (var attributeData in separateTableAttr) { if (attributeData.ConstructorArguments.Length < 2) { return null; } var rootTypeSymbol = attributeData.ConstructorArguments[0].Value as INamedTypeSymbol; var collectionName = attributeData.ConstructorArguments[1].Value?.ToString(); if (rootTypeSymbol == null || collectionName == null) { return null; } separateTableInfo[rootTypeSymbol.GetFullName()] = collectionName; } return separateTableInfo.Any() ? SeparateTableTypeInfo.Create(symbol, separateTableInfo) : null; } private static void GenerateRegistrationCode( SourceProductionContext context, Compilation compilation, IEnumerable separateTableTypeInfos) { SeparateTableInfo.Clear(); var separateTableTypeInfoList = separateTableTypeInfos.ToList(); // 获取当前程序集名称(仅用于注释) var assemblyName = compilation.AssemblyName ?? "Unknown"; // 生成代码文件 var builder = new SourceCodeBuilder(); // 添加 using builder.AddUsings( "System", "System.Collections.Generic", "Fantasy.Assembly", "Fantasy.Entitas", "Fantasy.Entitas.Interface", "Fantasy.Async" ); builder.AppendLine(); // 开始命名空间(固定使用 Fantasy.Generated) builder.BeginNamespace("Fantasy.Generated"); // 开始类定义(实现 IEntitySystemRegistrar 接口) builder.AddXmlComment($"Auto-generated Entity System registration class for {assemblyName}"); builder.BeginClass("SeparateTableRegistrar", "internal sealed", "ISeparateTableRegistrar"); // 生成字段用于存储已注册(用于 UnRegister) GenerateFields(builder, separateTableTypeInfoList); // 生成注册方法 GenerateRegisterMethod(builder, separateTableTypeInfoList); // 生成反注册方法 GenerateUnRegisterMethod(builder, separateTableTypeInfoList); // 结束类 builder.EndClass(); // 生成数据库帮助类 builder.Append(GenerateGenerateSeparateTableGeneratedExtensions().ToString()); // 结束命名空间 builder.EndNamespace(); // 输出源代码 context.AddSource("SeparateTableRegistrar.g.cs", builder.ToString()); } private static SourceCodeBuilder GenerateGenerateSeparateTableGeneratedExtensions() { var builder = new SourceCodeBuilder(); builder.AppendLine(); builder.Indent(1); builder.AddXmlComment("分表组件扩展方法。"); builder.AppendLine("public static class SeparateTableGeneratedExtensions"); builder.AppendLine("{"); builder.Indent(1); builder.AddXmlComment("从数据库加载指定实体的所有分表数据,并自动建立父子关系。"); builder.BeginMethod("public static FTask LoadWithSeparateTables(this T entity) where T : Entity, new()"); builder.AppendLine("return entity.Scene.SeparateTableComponent.LoadWithSeparateTables(entity);"); builder.EndMethod(); builder.AddXmlComment("将实体及其所有分表组件保存到数据库中。"); builder.BeginMethod("public static FTask PersistAggregate(this T entity) where T : Entity, new()"); builder.AppendLine("return entity.Scene.SeparateTableComponent.PersistAggregate(entity);"); builder.EndMethod(); builder.Unindent(); builder.AppendLine("}"); return builder; } private static void GenerateFields(SourceCodeBuilder builder, List separateTableTypeInfoList) { SeparateTableInfo.AppendLine("private readonly List _separateTableInfos = new List()"); SeparateTableInfo.Indent(2); SeparateTableInfo.AppendLine("{"); SeparateTableInfo.Indent(1); if (separateTableTypeInfoList.Any()) { foreach (var separateTableTypeInfo in separateTableTypeInfoList) { foreach (var separateTableInfo in separateTableTypeInfo.SeparateTableInfo) { SeparateTableInfo.AppendLine( $"new ISeparateTableRegistrar.SeparateTableInfo(typeof({separateTableInfo.Key}) ,typeof({separateTableTypeInfo.TypeFullName}) ,\"{separateTableInfo.Value}\"),"); } } } SeparateTableInfo.Unindent(); SeparateTableInfo.AppendLine("};"); builder.AppendLine(SeparateTableInfo.ToString()); } private static void GenerateRegisterMethod(SourceCodeBuilder builder, List separateTableTypeInfos) { builder.BeginMethod("public List Register()"); builder.AppendLine("return _separateTableInfos;"); builder.EndMethod(); builder.AppendLine(); } private static void GenerateUnRegisterMethod(SourceCodeBuilder builder, List separateTableTypeInfos) { builder.BeginMethod("public List UnRegister()"); builder.AppendLine("return _separateTableInfos;"); builder.EndMethod(); builder.AppendLine(); } private static bool IsSeparateTableClass(SyntaxNode node) { if (node is not ClassDeclarationSyntax classDecl) { return false; } // 快速检查是否有任何 Attribute if (classDecl.AttributeLists.Count == 0) { return false; } // 检查是否标记了 SeparateTableAttribute // 这里只做简单的语法级别检查,精确的语义检查在 GetSeparateTableTypeInfo 中进行 foreach (var attributeList in classDecl.AttributeLists) { foreach (var attribute in attributeList.Attributes) { var attributeName = attribute.Name.ToString(); // 匹配以下情况: // 1. [SeparateTable(...)] // 2. [SeparateTableAttribute(...)] // 3. [Fantasy.Entitas.Interface.SeparateTable(...)] // 4. [Fantasy.Entitas.Interface.SeparateTableAttribute(...)] // 5. [global::Fantasy.Entitas.Interface.SeparateTable(...)] if (attributeName == "SeparateTable" || attributeName == "SeparateTableAttribute" || attributeName == "Fantasy.Entitas.Interface.SeparateTable" || attributeName == "Fantasy.Entitas.Interface.SeparateTableAttribute" || attributeName == "global::Fantasy.Entitas.Interface.SeparateTable" || attributeName == "global::Fantasy.Entitas.Interface.SeparateTableAttribute") { return true; } } } return false; } private sealed class SeparateTableTypeInfo { public readonly Dictionary SeparateTableInfo; public readonly string TypeFullName; public readonly string TypeName; private SeparateTableTypeInfo(string typeFullName, string typeName, Dictionary separateTableInfo) { TypeFullName = typeFullName; TypeName = typeName; SeparateTableInfo = separateTableInfo; } public static SeparateTableTypeInfo Create(INamedTypeSymbol symbol, Dictionary separateTableInfo) { return new SeparateTableTypeInfo( symbol.GetFullName(), symbol.Name, separateTableInfo); } } } }