框架更新

This commit is contained in:
Bob.Song
2025-10-29 17:59:43 +08:00
parent fc18c8626a
commit a2cb248512
429 changed files with 7173 additions and 38748 deletions

View File

@@ -0,0 +1,31 @@
namespace Fantasy.SourceGenerator.Attributes
{
/// <summary>
/// 标记程序集启用 Source Generator 生成注册代码
/// 添加到 AssemblyInfo.cs 或任何文件:
/// [assembly: Fantasy.SourceGenerator.Attributes.EnableSourceGenerator]
/// </summary>
[System.AttributeUsage(System.AttributeTargets.Assembly)]
public sealed class EnableSourceGeneratorAttribute : System.Attribute
{
/// <summary>
/// 是否生成 Entity System 注册器
/// </summary>
public bool GenerateEntitySystem { get; set; } = true;
/// <summary>
/// 是否生成 Event Handler 注册器
/// </summary>
public bool GenerateEventHandler { get; set; } = true;
/// <summary>
/// 是否生成 OpCode Mapper 注册器
/// </summary>
public bool GenerateOpCodeMapper { get; set; } = true;
/// <summary>
/// 是否生成 Message Handler 注册器
/// </summary>
public bool GenerateMessageHandler { get; set; } = true;
}
}

View File

@@ -0,0 +1,101 @@
using System.Linq;
using Microsoft.CodeAnalysis;
namespace Fantasy.SourceGenerator.Common
{
/// <summary>
/// 编译环境检测帮助类
/// 提供检测 Fantasy 框架、Unity 环境等公共方法
/// </summary>
public static class CompilationHelper
{
/// <summary>
/// 检查是否定义了 Fantasy 框架的预编译符号
/// 只有定义了 FANTASY_NET的项目才会生成代码
/// </summary>
public static bool HasFantasyNETDefine(Compilation compilation)
{
// 遍历所有语法树的预处理符号
foreach (var tree in compilation.SyntaxTrees)
{
var defines = tree.Options.PreprocessorSymbolNames;
if (defines.Contains("FANTASY_NET"))
{
return true;
}
}
return false;
}
/// <summary>
/// 检查是否定义了 Fantasy 框架的预编译符号
/// 只有定义了 FANTASY_UNITY的项目才会生成代码
/// </summary>
public static bool HasFantasyUNITYDefine(Compilation compilation)
{
// 遍历所有语法树的预处理符号
foreach (var tree in compilation.SyntaxTrees)
{
var defines = tree.Options.PreprocessorSymbolNames;
if (defines.Contains("FANTASY_UNITY"))
{
return true;
}
}
return false;
}
/// <summary>
/// 检查是否定义了 Fantasy 框架的预编译符号
/// 只有定义了 FANTASY_NET 或 FANTASY_UNITY 的项目才会生成代码
/// </summary>
public static bool HasFantasyDefine(Compilation compilation)
{
// 遍历所有语法树的预处理符号
foreach (var tree in compilation.SyntaxTrees)
{
var defines = tree.Options.PreprocessorSymbolNames;
if (defines.Contains("FANTASY_NET") || defines.Contains("FANTASY_UNITY"))
{
return true;
}
}
return false;
}
/// <summary>
/// 检测是否是 Unity 编译环境
/// 优先检查是否引用了 UnityEngine 核心程序集或类型,这是最可靠的方式
/// </summary>
public static bool IsUnityCompilation(Compilation compilation)
{
// 方法1: 检查是否引用了 UnityEngine.CoreModule 或 UnityEngine 程序集(最可靠)
foreach (var reference in compilation.References)
{
if (reference is PortableExecutableReference peRef)
{
var display = peRef.Display ?? "";
// Unity 2017+ 使用模块化程序集
if (display.Contains("UnityEngine.CoreModule.dll") ||
display.Contains("UnityEngine.dll"))
{
return true;
}
}
}
// 方法2: 检查是否能够找到 UnityEngine 命名空间的核心类型
var unityMonoBehaviour = compilation.GetTypeByMetadataName("UnityEngine.MonoBehaviour");
var unityGameObject = compilation.GetTypeByMetadataName("UnityEngine.GameObject");
if (unityMonoBehaviour != null || unityGameObject != null)
{
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,43 @@
namespace Fantasy.SourceGenerator.Common
{
/// <summary>
/// Source Generator 使用的常量定义
/// </summary>
internal static class GeneratorConstants
{
/// <summary>
/// 生成文件的命名空间
/// </summary>
public const string GeneratedNamespace = "Fantasy.Generated";
/// <summary>
/// 诊断 ID 前缀
/// </summary>
public const string DiagnosticIdPrefix = "FANTASY";
/// <summary>
/// 生成的代码文件注释头
/// </summary>
public const string AutoGeneratedHeader = @"//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by Fantasy.SourceGenerator.
// Runtime Version: 1.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
#nullable enable
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
// ReSharper disable MergeIntoPattern
// ReSharper disable SuspiciousTypeConversion.Global
// ReSharper disable NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract
// ReSharper disable CheckNamespace
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
#pragma warning disable CS8603 // Possible null reference return.
#pragma warning disable CS8602 // Dereference of a possibly null reference.
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
";
}
}

View File

@@ -0,0 +1,45 @@
using System;
namespace Fantasy.SourceGenerator.Common
{
/// <summary>
/// HashCode 算法帮助类 (Source Generator 版本)
/// 用于在编译时计算类型哈希值
/// 注意:此实现必须与 Fantasy.Helper.HashCodeHelper.ComputeHash64 保持完全一致
/// </summary>
internal static class HashCodeHelper
{
/// <summary>
/// 使用 MurmurHash3 算法生成一个 long 的值
/// </summary>
/// <param name="str">输入字符串</param>
/// <returns>64位哈希值</returns>
public static long ComputeHash64(string str)
{
const ulong seed = 0xc58f1a7bc58f1a7bUL; // 64-bit seed
var hash = seed;
var c1 = 0x87c37b91114253d5UL;
var c2 = 0x4cf5ad432745937fUL;
for (var i = 0; i < str.Length; i++)
{
var k1 = (ulong)str[i];
k1 *= c1;
k1 = (k1 << 31) | (k1 >> (64 - 31));
k1 *= c2;
hash ^= k1;
hash = (hash << 27) | (hash >> (64 - 27));
hash = hash * 5 + 0x52dce729;
}
hash ^= (ulong)str.Length;
hash ^= hash >> 33;
hash *= 0xff51afd7ed558ccdUL;
hash ^= hash >> 33;
hash *= 0xc4ceb9fe1a85ec53UL;
hash ^= hash >> 33;
return (long)hash;
}
}
}

View File

@@ -0,0 +1,33 @@
// ReSharper disable CheckNamespace
//------------------------------------------------------------------------------
// 这个 IsExternalInit 类是一个 polyfill兼容性填充
// 用于在 .NET Standard 2.0 或较低版本的框架中启用 C# 9.0 的 init 访问器和 record 类型功能。
// 为什么需要它?
// C# 9.0 引入了 init 访问器(只在初始化时可设置的属性)
// 编译器在编译 init 属性时,会查找 IsExternalInit 类型
// 示例:
// public class Person
// {
// public string Name { get; init; } // 需要 IsExternalInit
// public int Age { get; init; }
// }
// 使用
// var person = new Person { Name = "Alice", Age = 30 };
// person.Name = "Bob"; // ❌ 编译错误init 属性只能在对象初始化时设置
// 不定义会怎样?
// 如果目标框架是 netstandard2.0 但没定义 IsExternalInit编译器会报错
// error CS0518: Predefined type 'System.Runtime.CompilerServices.IsExternalInit'
// is not defined or imported
// 实际应用场景
// 在 IncrementalGenerator 中,你可能会生成或使用带 init 的代码
//------------------------------------------------------------------------------
#if NETSTANDARD2_0 || NETFRAMEWORK
namespace System.Runtime.CompilerServices
{
/// <summary>
/// Polyfill for C# 9.0 record types in netstandard2.0
/// </summary>
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
internal static class IsExternalInit { }
}
#endif

View File

@@ -0,0 +1,134 @@
using Microsoft.CodeAnalysis;
using System.Collections.Generic;
using System.Linq;
namespace Fantasy.SourceGenerator.Common
{
/// <summary>
/// Roslyn 相关的扩展方法
/// </summary>
internal static class RoslynExtensions
{
/// <summary>
/// 检查类型是否实现了指定的接口(通过完全限定名)
/// </summary>
public static bool ImplementsInterface(this INamedTypeSymbol typeSymbol, string interfaceFullName)
{
return typeSymbol.AllInterfaces.Any(i => i.ToDisplayString() == interfaceFullName);
}
/// <summary>
/// 检查类型是否继承自指定的基类(通过完全限定名)
/// </summary>
public static bool InheritsFrom(this INamedTypeSymbol typeSymbol, string baseTypeFullName)
{
var current = typeSymbol.BaseType;
while (current != null)
{
if (current.ToDisplayString() == baseTypeFullName)
{
return true;
}
current = current.BaseType;
}
return false;
}
/// <summary>
/// 获取类型的完全限定名(包括命名空间)
/// </summary>
public static string GetFullName(this ITypeSymbol typeSymbol, bool includeGlobal = true)
{
var displayString = typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
return includeGlobal ? displayString : displayString.Replace("global::", "");
}
/// <summary>
/// 检查类型是否可以被实例化(非抽象、非接口、非泛型定义)
/// </summary>
public static bool IsInstantiable(this INamedTypeSymbol typeSymbol)
{
// 允许:具体的类(非抽象、非静态)
// 排除:抽象类、静态类、接口、开放泛型类型(如 MyClass<T> where T 未指定)
return typeSymbol is { IsAbstract: false, IsStatic: false, TypeKind: TypeKind.Class };
}
/// <summary>
/// 获取所有实现指定接口的类型
/// </summary>
public static IEnumerable<INamedTypeSymbol> GetTypesImplementingInterface(
this Compilation compilation,
string interfaceFullName)
{
var visitor = new InterfaceImplementationVisitor(interfaceFullName);
visitor.Visit(compilation.GlobalNamespace);
return visitor.ImplementingTypes;
}
/// <summary>
/// 转换为驼峰命名
/// </summary>
public static string ToCamelCase(this string name)
{
if (string.IsNullOrEmpty(name) || char.IsLower(name[0]))
{
return name;
}
return char.ToLowerInvariant(name[0]) + name.Substring(1);
}
/// <summary>
/// 访问器:查找实现特定接口的所有类型
/// </summary>
private class InterfaceImplementationVisitor : SymbolVisitor
{
private readonly string _interfaceFullName;
private readonly List<INamedTypeSymbol> _implementingTypes = new List<INamedTypeSymbol>();
public IReadOnlyList<INamedTypeSymbol> ImplementingTypes => _implementingTypes;
public InterfaceImplementationVisitor(string interfaceFullName)
{
_interfaceFullName = interfaceFullName;
}
public override void VisitNamespace(INamespaceSymbol symbol)
{
foreach (var member in symbol.GetMembers())
{
member.Accept(this);
}
}
public override void VisitNamedType(INamedTypeSymbol symbol)
{
if (symbol.IsInstantiable() && symbol.ImplementsInterface(_interfaceFullName))
{
_implementingTypes.Add(symbol);
}
// 递归访问嵌套类型
foreach (var nestedType in symbol.GetTypeMembers())
{
nestedType.Accept(this);
}
}
}
/// <summary>
/// 尝试获取泛型接口的类型参数
/// 例如IAwakeSystem&lt;PlayerEntity&gt; 返回 PlayerEntity
/// </summary>
public static ITypeSymbol? GetGenericInterfaceTypeArgument(
this INamedTypeSymbol typeSymbol,
string genericInterfaceName)
{
var matchingInterface = typeSymbol.AllInterfaces.FirstOrDefault(i =>
i.IsGenericType &&
i.ConstructedFrom.ToDisplayString() == genericInterfaceName);
return matchingInterface?.TypeArguments.FirstOrDefault();
}
}
}

View File

@@ -0,0 +1,211 @@
using System.Text;
namespace Fantasy.SourceGenerator.Common
{
/// <summary>
/// 辅助构建生成代码的工具类
/// </summary>
internal sealed class SourceCodeBuilder
{
private readonly StringBuilder _builder;
private int _indentLevel;
private const string IndentString = " "; // 4 空格缩进
public SourceCodeBuilder(int indentLevel = 0)
{
_builder = new StringBuilder();
_indentLevel = indentLevel;
}
/// <summary>
/// 增加缩进级别
/// </summary>
public SourceCodeBuilder Indent(int indentLevel = 1)
{
_indentLevel += indentLevel;
return this;
}
/// <summary>
/// 减少缩进级别
/// </summary>
public SourceCodeBuilder Unindent()
{
if (_indentLevel > 0)
{
_indentLevel--;
}
return this;
}
public void Append(string code = "")
{
_builder.Append(code);
}
/// <summary>
/// 添加一行代码(自动处理缩进)
/// </summary>
public SourceCodeBuilder AppendLine(string code = "", bool indent = true)
{
if (string.IsNullOrEmpty(code))
{
_builder.AppendLine();
}
else
{
if (indent)
{
for (int i = 0; i < _indentLevel; i++)
{
_builder.Append(IndentString);
}
}
_builder.AppendLine(code);
}
return this;
}
/// <summary>
/// 添加代码块开始 {
/// </summary>
public SourceCodeBuilder OpenBrace()
{
AppendLine("{");
Indent();
return this;
}
/// <summary>
/// 添加代码块结束 }
/// </summary>
public SourceCodeBuilder CloseBrace(bool semicolon = false)
{
Unindent();
AppendLine(semicolon ? "};" : "}");
return this;
}
/// <summary>
/// 添加 using 语句
/// </summary>
public SourceCodeBuilder AddUsing(string @namespace)
{
AppendLine($"using {@namespace};");
return this;
}
/// <summary>
/// 添加多个 using 语句
/// </summary>
public SourceCodeBuilder AddUsings(params string[] namespaces)
{
foreach (var ns in namespaces)
{
AddUsing(ns);
}
return this;
}
/// <summary>
/// 开始命名空间
/// </summary>
public SourceCodeBuilder BeginNamespace(string @namespace)
{
AppendLine($"namespace {@namespace}");
OpenBrace();
return this;
}
/// <summary>
/// 结束命名空间
/// </summary>
public SourceCodeBuilder EndNamespace()
{
CloseBrace();
return this;
}
/// <summary>
/// 开始类定义
/// </summary>
public SourceCodeBuilder BeginClass(string className, string? modifiers = "internal static", string? baseTypes = null)
{
var classDeclaration = $"{modifiers} class {className}";
if (!string.IsNullOrEmpty(baseTypes))
{
classDeclaration += $" : {baseTypes}";
}
AppendLine(classDeclaration);
OpenBrace();
return this;
}
/// <summary>
/// 结束类定义
/// </summary>
public SourceCodeBuilder EndClass()
{
CloseBrace();
return this;
}
/// <summary>
/// 开始方法定义
/// </summary>
public SourceCodeBuilder BeginMethod(string signature)
{
AppendLine(signature);
OpenBrace();
return this;
}
/// <summary>
/// 结束方法定义
/// </summary>
public SourceCodeBuilder EndMethod()
{
CloseBrace();
return this;
}
/// <summary>
/// 添加注释
/// </summary>
public SourceCodeBuilder AddComment(string comment)
{
AppendLine($"// {comment}");
return this;
}
/// <summary>
/// 添加 XML 文档注释
/// </summary>
public SourceCodeBuilder AddXmlComment(string summary)
{
AppendLine("/// <summary>");
AppendLine($"/// {summary}");
AppendLine("/// </summary>");
return this;
}
/// <summary>
/// 构建最终代码
/// </summary>
public override string ToString()
{
return _builder.ToString();
}
/// <summary>
/// 清空构建器
/// </summary>
public void Clear()
{
_builder.Clear();
_indentLevel = 0;
}
}
}

View File

@@ -0,0 +1,40 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<IsRoslynComponent>true</IsRoslynComponent>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<!-- 帮助 IDE 识别这是一个 Source Generator -->
<DevelopmentDependency>true</DevelopmentDependency>
<IncludeBuildOutput>false</IncludeBuildOutput>
</PropertyGroup>
<!-- 为 Unity 构建使用低版本 Roslyn (Unity 2020.2-2022.x 使用 Roslyn 4.0-4.3) -->
<PropertyGroup Condition="'$(Configuration)' == 'Unity' OR '$(Configuration)' == 'UnityDebug'">
<DefineConstants>$(DefineConstants);UNITY_COMPATIBLE</DefineConstants>
</PropertyGroup>
<!-- Unity 兼容版本 - 使用 Roslyn 4.0.1 (兼容 Unity 2020.2+) -->
<ItemGroup Condition="'$(Configuration)' == 'Unity' OR '$(Configuration)' == 'UnityDebug'">
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" PrivateAssets="all" />
</ItemGroup>
<!-- .NET 版本 - 使用最新 Roslyn (用于 .NET 8/9 项目) -->
<ItemGroup Condition="'$(Configuration)' != 'Unity' AND '$(Configuration)' != 'UnityDebug'">
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<!-- 让生成的代码对用户可见 (调试用) -->
<CompilerVisibleProperty Include="RootNamespace" />
<CompilerVisibleProperty Include="ProjectDir" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,259 @@
using Fantasy.SourceGenerator.Common;
using Microsoft.CodeAnalysis;
namespace Fantasy.SourceGenerator.Generators
{
/// <summary>
/// 程序集初始化器生成器
/// 为每个 Fantasy 项目生成 ModuleInitializer在程序集加载时自动注册到框架
/// 支持 Native AOT无需运行时反射
/// </summary>
[Generator]
public class AssemblyInitializerGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 获取编译信息
var compilationProvider = context.CompilationProvider;
// 注册源代码输出
context.RegisterSourceOutput(compilationProvider, (spc, compilation) =>
{
GenerateModuleInitializer(spc, compilation);
});
}
private static void GenerateModuleInitializer(
SourceProductionContext context,
Compilation compilation)
{
// 检查是否定义了 FANTASY_NET 或 FANTASY_UNITY 预编译符号
if (!CompilationHelper.HasFantasyDefine(compilation))
{
// 不是 Fantasy 框架项目,跳过代码生成
return;
}
var assemblyName = compilation.AssemblyName ?? "Unknown";
// 检测是否是 Unity 环境
var isUnity = CompilationHelper.IsUnityCompilation(compilation);
var builder = new SourceCodeBuilder();
// 添加文件头
builder.AppendLine(GeneratorConstants.AutoGeneratedHeader);
// 添加 using
if (isUnity)
{
builder.AddUsings(
"System",
"UnityEngine"
);
}
else
{
builder.AddUsings(
"System",
"System.Runtime.CompilerServices"
);
}
builder.AppendLine();
// 开始命名空间
builder.BeginNamespace(GeneratorConstants.GeneratedNamespace);
// 添加类注释
builder.AddXmlComment($"Auto-generated assembly initializer for {assemblyName}");
builder.AddXmlComment("This class is automatically invoked when the assembly is loaded via ModuleInitializer");
// 开始类定义
builder.BeginClass("AssemblyInitializer", "internal static");
// 添加字段
builder.AppendLine("private static bool _initialized;");
builder.AppendLine("private static long _assemblyManifestId;");
builder.AppendLine();
// 生成 ModuleInitializer 方法
GenerateInitializeMethod(builder, assemblyName, isUnity);
// 生成卸载方法
GenerateUnloadMethod(builder, isUnity);
// 结束 AssemblyInitializer 类
builder.EndClass();
builder.AppendLine();
// 生成 AssemblyMarker 类(用于强制加载程序集)
// 类名包含程序集名称以避免冲突,将特殊字符替换为下划线
var markerClassName = assemblyName.Replace("-", "_").Replace(".", "_") + "_AssemblyMarker";
builder.AddXmlComment($"Public marker class for forcing {assemblyName} assembly load");
builder.AddXmlComment("Access this type to ensure the assembly is loaded and ModuleInitializer executes");
builder.BeginClass(markerClassName, "public static");
builder.AppendLine("/// <summary>");
builder.AppendLine("/// Call this method to ensure the assembly is loaded");
builder.AppendLine("/// This is useful when loading assemblies dynamically via reflection");
builder.AppendLine("/// </summary>");
builder.BeginMethod("public static void EnsureLoaded()");
builder.AppendLine("// Accessing this method ensures the assembly is loaded");
builder.AppendLine("// ModuleInitializer will execute automatically when assembly loads");
builder.EndMethod();
builder.EndClass();
// 结束命名空间
builder.EndNamespace();
// 输出源代码
context.AddSource("AssemblyInitializer.g.cs", builder.ToString());
}
private static void GenerateInitializeMethod(SourceCodeBuilder builder, string assemblyName, bool isUnity)
{
if (isUnity)
{
builder.AddXmlComment(
"Unity runtime initializer - automatically called when entering play mode or on app start");
builder.AppendLine("[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]");
builder.BeginMethod("internal static void Initialize()");
}
else
{
builder.AddXmlComment("Module initializer - automatically called when assembly is loaded");
builder.AppendLine("[ModuleInitializer]");
builder.BeginMethod("internal static void Initialize()");
}
// 防止重复初始化
builder.AppendLine("if (_initialized)");
builder.OpenBrace();
builder.AppendLine("return;");
builder.CloseBrace();
builder.AppendLine();
builder.AppendLine("_initialized = true;");
builder.AppendLine();
// 获取程序集并计算唯一标识
builder.AddComment("Get assembly and calculate manifest ID");
builder.AppendLine("var assembly = typeof(AssemblyInitializer).Assembly;");
builder.AppendLine(
$"_assemblyManifestId = Fantasy.Helper.HashCodeHelper.ComputeHash64(assembly.GetName().Name ?? \"{assemblyName}\");");
builder.AppendLine();
// 注册卸载事件(用于热更新支持)
builder.AddComment("Register auto-unload for collectible AssemblyLoadContext (hot-reload support)");
if (isUnity)
{
builder.AppendLine(
"#if !UNITY_EDITOR && !UNITY_STANDALONE && !UNITY_ANDROID && !UNITY_IOS && !UNITY_WEBGL");
}
builder.AppendLine("var loadContext = System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(assembly);");
builder.AppendLine(
"if (loadContext != null && loadContext != System.Runtime.Loader.AssemblyLoadContext.Default)");
builder.OpenBrace();
builder.AppendLine("loadContext.Unloading += OnAssemblyUnloading;");
builder.CloseBrace();
if (isUnity)
{
builder.AppendLine("#endif");
}
builder.AppendLine();
// 声明所有可能的注册器变量
builder.AddComment("Declare registrar variables");
builder.AppendLine("Fantasy.Assembly.INetworkProtocolRegistrar? networkProtocolRegistrar = null;");
builder.AppendLine("Fantasy.Assembly.IEventSystemRegistrar? eventSystemRegistrar = null;");
builder.AppendLine("Fantasy.Assembly.IEntitySystemRegistrar? entitySystemRegistrar = null;");
builder.AppendLine("Fantasy.Assembly.IMessageHandlerResolver? messageHandlerResolverRegistrar = null;");
builder.AppendLine(
"Fantasy.Assembly.IEntityTypeCollectionRegistrar? entityTypeCollectionRegistrar = null;");
builder.AppendLine(
"Fantasy.Assembly.INetworkProtocolOpCodeResolver? networkProtocolOpCodeResolverRegistrar = null;");
builder.AppendLine(
"Fantasy.Assembly.INetworkProtocolResponseTypeResolver? networkProtocolResponseTypeResolverRegistrar = null;");
builder.AppendLine("#if FANTASY_NET", false);
builder.AppendLine(
"Fantasy.Assembly.ISeparateTableRegistrar? separateTableRegistrar = null;");
builder.AppendLine("#endif", false);
builder.AppendLine();
// 尝试创建各个注册器(如果存在)
builder.AddComment("Try to create registrars if they were generated in this assembly");
GenerateTryCreateRegistrar(builder, "NetworkProtocol", "networkProtocolRegistrar");
GenerateTryCreateRegistrar(builder, "EventSystem", "eventSystemRegistrar");
GenerateTryCreateRegistrar(builder, "EntitySystem", "entitySystemRegistrar");
GenerateTryCreateRegistrar(builder, "MessageHandlerResolver", "messageHandlerResolverRegistrar");
GenerateTryCreateRegistrar(builder, "EntityTypeCollection", "entityTypeCollectionRegistrar");
GenerateTryCreateRegistrar(builder, "NetworkProtocolOpCodeResolver", "networkProtocolOpCodeResolverRegistrar");
GenerateTryCreateRegistrar(builder, "NetworkProtocolResponseTypeResolver", "networkProtocolResponseTypeResolverRegistrar");
builder.AppendLine("#if FANTASY_NET", false);
GenerateTryCreateRegistrar(builder, "SeparateTable", "separateTableRegistrar");
builder.AppendLine("#endif", false);
builder.AppendLine();
// 注册到框架
builder.AddComment("Register complete AssemblyManifest to the framework");
builder.AppendLine("#if FANTASY_NET", false);
builder.AppendLine("Fantasy.Assembly.AssemblyManifest.Register(");
builder.Indent();
builder.AppendLine("_assemblyManifestId,");
builder.AppendLine("assembly,");
builder.AppendLine("networkProtocolRegistrar,");
builder.AppendLine("eventSystemRegistrar,");
builder.AppendLine("entitySystemRegistrar,");
builder.AppendLine("messageHandlerResolverRegistrar,");
builder.AppendLine("entityTypeCollectionRegistrar,");
builder.AppendLine("separateTableRegistrar,");
builder.AppendLine("networkProtocolOpCodeResolverRegistrar,");
builder.AppendLine("networkProtocolResponseTypeResolverRegistrar);");
builder.Unindent();
builder.AppendLine("#endif", false);
builder.AppendLine("#if FANTASY_UNITY", false);
builder.AppendLine("Fantasy.Assembly.AssemblyManifest.Register(");
builder.Indent();
builder.AppendLine("_assemblyManifestId,");
builder.AppendLine("assembly,");
builder.AppendLine("networkProtocolRegistrar,");
builder.AppendLine("eventSystemRegistrar,");
builder.AppendLine("entitySystemRegistrar,");
builder.AppendLine("messageHandlerResolverRegistrar,");
builder.AppendLine("entityTypeCollectionRegistrar,");
builder.AppendLine("networkProtocolOpCodeResolverRegistrar,");
builder.AppendLine("networkProtocolResponseTypeResolverRegistrar);");
builder.Unindent();
builder.AppendLine("#endif", false);
builder.EndMethod();
}
private static void GenerateUnloadMethod(SourceCodeBuilder builder, bool isUnity)
{
builder.AppendLine();
builder.AddXmlComment("Called when AssemblyLoadContext is unloading (for hot-reload support)");
// Unity 环境下AssemblyLoadContext 仅在非编辑器/非独立平台可用
if (isUnity)
{
builder.AppendLine("#if !UNITY_EDITOR && !UNITY_STANDALONE && !UNITY_ANDROID && !UNITY_IOS && !UNITY_WEBGL");
}
builder.BeginMethod("private static void OnAssemblyUnloading(System.Runtime.Loader.AssemblyLoadContext context)");
builder.AddComment("Unregister from framework");
builder.AppendLine("if (_assemblyManifestId != 0)");
builder.OpenBrace();
builder.AppendLine("Fantasy.Assembly.AssemblyManifest.Unregister(_assemblyManifestId);");
builder.CloseBrace();
builder.EndMethod();
if (isUnity)
{
builder.AppendLine("#endif");
}
}
private static void GenerateTryCreateRegistrar(
SourceCodeBuilder builder,
string registrarName,
string variableName)
{
var typeName = $"Fantasy.Generated.{registrarName}Registrar";
builder.AppendLine($"{variableName} = new {typeName}();");
}
}
}

View File

@@ -0,0 +1,338 @@
using Fantasy.SourceGenerator.Common;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Collections.Generic;
using System.Linq;
using System.Text;
#pragma warning disable CS8602 // Dereference of a possibly null reference.
namespace Fantasy.SourceGenerator.Generators
{
/// <summary>
/// Entity System 注册代码生成器
/// 自动生成 EntityComponent 所需的 System 注册代码,替代运行时反射
/// </summary>
[Generator]
public partial class EntitySystemGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 查找所有实现了 IEntitySystem 相关接口的类
var systemTypes = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: static (node, _) => IsSystemClass(node),
transform: static (ctx, _) => GetSystemTypeInfo(ctx))
.Where(static info => info != null)
.Collect();
// 组合编译信息和找到的类型
var compilationAndTypes = context.CompilationProvider.Combine(systemTypes);
// 注册源代码输出
context.RegisterSourceOutput(compilationAndTypes, static (spc, source) =>
{
// 检查1: 是否定义了 FANTASY_NET 或 FANTASY_UNITY 预编译符号
if (!CompilationHelper.HasFantasyDefine(source.Left))
{
return;
}
// 检查2: 是否引用了 Fantasy 框架的核心类型
if (source.Left.GetTypeByMetadataName("Fantasy.Assembly.IEntitySystemRegistrar") == null)
{
return;
}
GenerateRegistrationCode(spc, source.Left, source.Right!);
});
}
private static EntitySystemTypeInfo? GetSystemTypeInfo(GeneratorSyntaxContext context)
{
var classDecl = (ClassDeclarationSyntax)context.Node;
if (context.SemanticModel.GetDeclaredSymbol(classDecl) is not INamedTypeSymbol symbol || !symbol.IsInstantiable())
{
return null;
}
var baseType = symbol.BaseType;
if (!baseType.IsGenericType)
{
return null;
}
return baseType.Name switch
{
"AwakeSystem" => EntitySystemTypeInfo.Create(EntitySystemType.AwakeSystem, symbol),
"UpdateSystem" => EntitySystemTypeInfo.Create(EntitySystemType.UpdateSystem, symbol),
"DestroySystem" => EntitySystemTypeInfo.Create(EntitySystemType.DestroySystem, symbol),
"DeserializeSystem" => EntitySystemTypeInfo.Create(EntitySystemType.DeserializeSystem, symbol),
"LateUpdateSystem" => EntitySystemTypeInfo.Create(EntitySystemType.LateUpdateSystem, symbol),
_ => null
};
}
private static void GenerateRegistrationCode(
SourceProductionContext context,
Compilation compilation,
IEnumerable<EntitySystemTypeInfo> systemTypes)
{
var entitySystemTypeInfos = systemTypes.ToList();
// 获取当前程序集名称(仅用于注释)
var assemblyName = compilation.AssemblyName ?? "Unknown";
// 生成代码文件
var builder = new SourceCodeBuilder();
// 添加文件头
builder.AppendLine(GeneratorConstants.AutoGeneratedHeader);
// 添加 using
builder.AddUsings(
"System",
"System.Collections.Generic",
"Fantasy.Assembly",
"Fantasy.Entitas",
"Fantasy.Entitas.Interface"
);
builder.AppendLine();
// 开始命名空间(固定使用 Fantasy.Generated
builder.BeginNamespace("Fantasy.Generated");
// 开始类定义(实现 IEntitySystemRegistrar 接口)
builder.AddXmlComment($"Auto-generated Entity System registration class for {assemblyName}");
builder.BeginClass("EntitySystemRegistrar", "internal sealed", "IEntitySystemRegistrar");
// 生成字段用于存储 System 实例
GenerateFields(builder, entitySystemTypeInfos);
// 生成注册方法
GenerateRegisterMethod(builder, entitySystemTypeInfos);
// 生成反注册方法
GenerateUnRegisterMethod(builder, entitySystemTypeInfos);
// 结束类和命名空间
builder.EndClass();
builder.EndNamespace();
// 输出源代码
context.AddSource("EntitySystemRegistrar.g.cs", builder.ToString());
}
private static void GenerateFields(SourceCodeBuilder builder, List<EntitySystemTypeInfo> entitySystemTypeInfos)
{
builder.AddComment("Store registered entity system for UnRegister");
if (!entitySystemTypeInfos.Any())
{
return;
}
foreach (var eventSystemTypeInfo in entitySystemTypeInfos)
{
var fieldName = $"_{eventSystemTypeInfo.TypeName.ToCamelCase()}";
builder.AppendLine($"private {eventSystemTypeInfo.GlobalTypeFullName} {fieldName} = new {eventSystemTypeInfo.GlobalTypeFullName}();");
builder.AppendLine($"private const long _typeHashCode{fieldName} = {eventSystemTypeInfo.EntityTypeHashCode};");
}
builder.AppendLine();
}
private static void GenerateRegisterMethod(SourceCodeBuilder builder, List<EntitySystemTypeInfo> entitySystemTypeInfos)
{
builder.AddXmlComment("Register all Entity Systems to the dictionaries");
builder.AppendLine("#if FANTASY_NET", false);
builder.BeginMethod(
"public void RegisterSystems(" +
"Dictionary<long, Action<Entity>> awakeSystems, " +
"Dictionary<long, Action<Entity>> updateSystems, " +
"Dictionary<long, Action<Entity>> destroySystems, " +
"Dictionary<long, Action<Entity>> deserializeSystems)");
builder.AppendLine("#endif", false);
builder.Unindent();
builder.AppendLine("#if FANTASY_UNITY", false);
builder.BeginMethod(
"public void RegisterSystems(" +
"Dictionary<long, Action<Entity>> awakeSystems, " +
"Dictionary<long, Action<Entity>> updateSystems, " +
"Dictionary<long, Action<Entity>> destroySystems, " +
"Dictionary<long, Action<Entity>> deserializeSystems, " +
"Dictionary<long, Action<Entity>> lateUpdateSystems)");
builder.AppendLine("#endif", false);
if (entitySystemTypeInfos.Any())
{
foreach (var systemTypeInfo in entitySystemTypeInfos)
{
var fieldName = $"_{systemTypeInfo.TypeName.ToCamelCase()}";
switch (systemTypeInfo.EntitySystemType)
{
case EntitySystemType.AwakeSystem:
{
builder.AppendLine($"awakeSystems.Add(_typeHashCode{fieldName}, {fieldName}.Invoke);");
continue;
}
case EntitySystemType.UpdateSystem:
{
builder.AppendLine($"updateSystems.Add(_typeHashCode{fieldName}, {fieldName}.Invoke);");
continue;
}
case EntitySystemType.DestroySystem:
{
builder.AppendLine($"destroySystems.Add(_typeHashCode{fieldName}, {fieldName}.Invoke);");
continue;
}
case EntitySystemType.DeserializeSystem:
{
builder.AppendLine($"deserializeSystems.Add(_typeHashCode{fieldName}, {fieldName}.Invoke);");
continue;
}
case EntitySystemType.LateUpdateSystem:
{
builder.AppendLine("#if FANTASY_UNITY", false);
builder.AppendLine($"awakeSystems.Add(_typeHashCode{fieldName}, {fieldName}.Invoke);");
builder.AppendLine("#endif", false);
continue;
}
}
}
}
builder.EndMethod();
builder.AppendLine();
}
private static void GenerateUnRegisterMethod(SourceCodeBuilder builder, List<EntitySystemTypeInfo> entitySystemTypeInfos)
{
builder.AddXmlComment("Unregister all Entity Systems from the dictionaries");
builder.AppendLine("#if FANTASY_NET", false);
builder.BeginMethod(
"public void UnRegisterSystems(" +
"Dictionary<long, Action<Entity>> awakeSystems, " +
"Dictionary<long, Action<Entity>> updateSystems, " +
"Dictionary<long, Action<Entity>> destroySystems, " +
"Dictionary<long, Action<Entity>> deserializeSystems)");
builder.AppendLine("#endif", false);
builder.Unindent();
builder.AppendLine("#if FANTASY_UNITY", false);
builder.BeginMethod(
"public void UnRegisterSystems(" +
"Dictionary<long, Action<Entity>> awakeSystems, " +
"Dictionary<long, Action<Entity>> updateSystems, " +
"Dictionary<long, Action<Entity>> destroySystems, " +
"Dictionary<long, Action<Entity>> deserializeSystems, " +
"Dictionary<long, Action<Entity>> lateUpdateSystems)");
builder.AppendLine("#endif", false);
if (entitySystemTypeInfos.Any())
{
foreach (var systemTypeInfo in entitySystemTypeInfos)
{
var fieldName = $"_{systemTypeInfo.TypeName.ToCamelCase()}";
switch (systemTypeInfo.EntitySystemType)
{
case EntitySystemType.AwakeSystem:
{
builder.AppendLine($"awakeSystems.Remove(_typeHashCode{fieldName});");
continue;
}
case EntitySystemType.UpdateSystem:
{
builder.AppendLine($"updateSystems.Remove(_typeHashCode{fieldName});");
continue;
}
case EntitySystemType.DestroySystem:
{
builder.AppendLine($"destroySystems.Remove(_typeHashCode{fieldName});");
continue;
}
case EntitySystemType.DeserializeSystem:
{
builder.AppendLine($"deserializeSystems.Remove(_typeHashCode{fieldName});");
continue;
}
case EntitySystemType.LateUpdateSystem:
{
builder.AppendLine("#if FANTASY_UNITY", false);
builder.AppendLine($"lateUpdateSystem.Remove(_typeHashCode{fieldName});");
builder.AppendLine("#endif", false);
continue;
}
}
}
}
builder.EndMethod();
builder.AppendLine();
}
private static bool IsSystemClass(SyntaxNode node)
{
if (node is not ClassDeclarationSyntax classDecl)
{
return false;
}
// 必须有基类型列表(继承抽象类)
if (classDecl.BaseList == null || classDecl.BaseList.Types.Count == 0)
{
return false;
}
// 快速检查是否包含可能的 EntitySystem 基类名称
var baseListText = classDecl.BaseList.ToString();
return baseListText.Contains("AwakeSystem") ||
baseListText.Contains("UpdateSystem") ||
baseListText.Contains("DestroySystem") ||
baseListText.Contains("DeserializeSystem") ||
baseListText.Contains("LateUpdateSystem");
}
private enum EntitySystemType
{
None,
AwakeSystem,
UpdateSystem,
DestroySystem,
DeserializeSystem,
LateUpdateSystem
}
private sealed class EntitySystemTypeInfo
{
public readonly EntitySystemType EntitySystemType;
public readonly string GlobalTypeFullName;
public readonly string TypeFullName;
public readonly string TypeName;
public readonly long EntityTypeHashCode; // 预计算的实体类型哈希值
public readonly string EntityTypeFullName; // 实体类型的完整名称(用于注释)
private EntitySystemTypeInfo(
EntitySystemType entitySystemType,
string globalTypeFullName,
string typeFullName,
string typeName,
long entityTypeHashCode,
string entityTypeFullName)
{
EntitySystemType = entitySystemType;
GlobalTypeFullName = globalTypeFullName;
TypeFullName = typeFullName;
TypeName = typeName;
EntityTypeHashCode = entityTypeHashCode;
EntityTypeFullName = entityTypeFullName;
}
public static EntitySystemTypeInfo Create(EntitySystemType entitySystemType, INamedTypeSymbol symbol)
{
// 获取泛型参数 T (例如AwakeSystem<T> 中的 T)
var entityType = symbol.BaseType?.TypeArguments.FirstOrDefault();
var entityTypeFullName = entityType?.GetFullName(false) ?? "Unknown";
// 使用与运行时相同的算法计算哈希值
var entityTypeHashCode = HashCodeHelper.ComputeHash64(entityTypeFullName);
return new EntitySystemTypeInfo(
entitySystemType,
symbol.GetFullName(),
symbol.GetFullName(false),
symbol.Name,
entityTypeHashCode,
entityTypeFullName);
}
}
}
}

View File

@@ -0,0 +1,180 @@
using Fantasy.SourceGenerator.Common;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace Fantasy.SourceGenerator.Generators
{
[Generator]
public partial class EntityTypeCollectionGenerate : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 查找所有实现了 EventSystem 相关抽象类的类
var protoBufTypes = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: static (node, _) => IsEntityClass(node),
transform: static (ctx, _) => GetEntityTypeInfo(ctx))
.Where(static info => info != null)
.Collect();
// 组合编译信息和找到的类型
var compilationAndTypes = context.CompilationProvider.Combine(protoBufTypes);
// 注册源代码输出
context.RegisterSourceOutput(compilationAndTypes, static (spc, source) =>
{
// 检查1: 是否定义了 FANTASY_NET 或 FANTASY_UNITY 预编译符号
if (!CompilationHelper.HasFantasyDefine(source.Left))
{
return;
}
// 检查2: 是否引用了 Fantasy 框架的核心类型
if (source.Left.GetTypeByMetadataName("Fantasy.Assembly.IEntityTypeCollectionRegistrar") == null)
{
return;
}
GenerateRegistrationCode(spc, source.Left, source.Right!);
});
}
/// <summary>
/// 生成注册代码
/// </summary>
private static void GenerateRegistrationCode(
SourceProductionContext context,
Compilation compilation,
IEnumerable<EntityTypeInfo> entityTypeInfos)
{
var entityTypeList = entityTypeInfos.ToList();
// 获取当前程序集名称(仅用于注释)
var assemblyName = compilation.AssemblyName ?? "Unknown";
var builder = new SourceCodeBuilder();
// 添加文件头
builder.AppendLine(GeneratorConstants.AutoGeneratedHeader);
// 添加 using
builder.AddUsings(
"System",
"System.Collections.Generic",
"Fantasy.Assembly",
"Fantasy.DataStructure.Collection",
"Fantasy.Event"
);
builder.AppendLine();
// 开始命名空间(固定使用 Fantasy.Generated
builder.BeginNamespace("Fantasy.Generated");
// 开始类定义(实现 IEntityTypeCollectionRegistrar 接口)
builder.AddXmlComment($"Automatically generated Entity Type collection class for {assemblyName}");
builder.BeginClass("EntityTypeCollectionRegistrar", "internal sealed", "IEntityTypeCollectionRegistrar");
// 生成 GetEntityTypes 方法
GetEntityTypesMethod(builder, entityTypeList);
builder.AppendLine();
// 结束类和命名空间
builder.EndClass();
builder.EndNamespace();
// 输出源代码
context.AddSource("EntityTypeCollectionRegistrar.g.cs", builder.ToString());
}
private static void GetEntityTypesMethod(SourceCodeBuilder builder, List<EntityTypeInfo> entityTypeInfos)
{
builder.AddXmlComment("All Entity Types");
builder.BeginMethod("public List<Type> GetEntityTypes()");
if (entityTypeInfos.Any())
{
builder.AppendLine($"return new List<Type>({entityTypeInfos.Count})");
builder.AppendLine("{");
builder.Indent();
foreach (var system in entityTypeInfos)
{
builder.AppendLine($"typeof({system.EntityTypeFullName}),");
}
builder.Unindent();
builder.AppendLine("};");
builder.AppendLine();
}
else
{
builder.AppendLine($"return new List<Type>();");
}
builder.EndMethod();
}
private static bool IsEntityClass(SyntaxNode node)
{
if (node is not ClassDeclarationSyntax classDecl)
{
return false;
}
// 必须有基类型列表(实现接口)
return classDecl.BaseList != null && classDecl.BaseList.Types.Any();
}
private static EntityTypeInfo? GetEntityTypeInfo(GeneratorSyntaxContext context)
{
var classDecl = (ClassDeclarationSyntax)context.Node;
var semanticModel = context.SemanticModel;
// 检查是否继承自 Entity 或 Entity<T>
if (!InheritsFromEntity(classDecl, semanticModel))
{
return null;
}
var symbol = context.SemanticModel.GetDeclaredSymbol(classDecl) as INamedTypeSymbol;
if (symbol == null || !symbol.IsInstantiable())
{
return null;
}
return new EntityTypeInfo(
symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
symbol.Name
);
}
private static bool InheritsFromEntity(ClassDeclarationSyntax classDecl, SemanticModel semanticModel)
{
if (classDecl.BaseList == null)
{
return false;
}
foreach (var baseType in classDecl.BaseList.Types)
{
var typeInfo = semanticModel.GetTypeInfo(baseType.Type);
var baseTypeSymbol = typeInfo.Type as INamedTypeSymbol;
if (baseTypeSymbol == null)
{
continue;
}
// 检查是否是 Entity非泛型
if (baseTypeSymbol.Name == "Entity" && baseTypeSymbol.Arity == 0)
{
return true;
}
// 检查是否是 Entity<T>(泛型)
if (baseTypeSymbol.IsGenericType)
{
var originalDef = baseTypeSymbol.OriginalDefinition;
if (originalDef.Name == "Entity" && originalDef.Arity == 1)
{
return true;
}
}
}
return false;
}
private sealed record EntityTypeInfo(
string EntityTypeFullName,
string EntityTypeName
);
}
}

View File

@@ -0,0 +1,305 @@
using Fantasy.SourceGenerator.Common;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Collections.Generic;
using System.Linq;
using System.Text;
// ReSharper disable AssignNullToNotNullAttribute
namespace Fantasy.SourceGenerator.Generators
{
/// <summary>
/// Event System 注册代码生成器
/// 自动生成 EventComponent 所需的 Event System 注册代码,替代运行时反射
/// </summary>
[Generator]
public partial class EventSystemGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 查找所有实现了 EventSystem 相关抽象类的类
var eventSystemTypes = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: static (node, _) => IsEventSystemClass(node),
transform: static (ctx, _) => GetEventSystemTypeInfo(ctx))
.Where(static info => info != null)
.Collect();
// 组合编译信息和找到的类型
var compilationAndTypes = context.CompilationProvider.Combine(eventSystemTypes);
// 注册源代码输出
context.RegisterSourceOutput(compilationAndTypes, static (spc, source) =>
{
// 检查1: 是否定义了 FANTASY_NET 或 FANTASY_UNITY 预编译符号
if (!CompilationHelper.HasFantasyDefine(source.Left))
{
return;
}
// 检查2: 是否引用了 Fantasy 框架的核心类型
if (source.Left.GetTypeByMetadataName("Fantasy.Assembly.IEventSystemRegistrar") == null)
{
return;
}
GenerateRegistrationCode(spc, source.Left, source.Right!);
});
}
/// <summary>
/// 提取 EventSystem 类型信息
/// </summary>
private static EventSystemTypeInfo? GetEventSystemTypeInfo(GeneratorSyntaxContext context)
{
var classDecl = (ClassDeclarationSyntax)context.Node;
if (context.SemanticModel.GetDeclaredSymbol(classDecl) is not INamedTypeSymbol symbol || !symbol.IsInstantiable())
{
return null;
}
if (symbol.BaseType == null)
{
return null;
}
var baseType = symbol.BaseType;
if (!baseType.IsGenericType)
{
return null;
}
return baseType.Name switch
{
"EventSystem" => EventSystemTypeInfo.Create(EventSystemType.EventSystem, symbol),
"AsyncEventSystem" => EventSystemTypeInfo.Create(EventSystemType.AsyncEventSystem, symbol),
"SphereEventSystem" => EventSystemTypeInfo.Create(EventSystemType.SphereEventSystem, symbol),
_ => null
};
}
/// <summary>
/// 生成注册代码
/// </summary>
private static void GenerateRegistrationCode(
SourceProductionContext context,
Compilation compilation,
IEnumerable<EventSystemTypeInfo> eventSystemTypes)
{
var eventSystems = eventSystemTypes.ToList();
// 获取当前程序集名称(仅用于注释)
var assemblyName = compilation.AssemblyName ?? "Unknown";
// 生成代码文件
var builder = new SourceCodeBuilder();
// 添加文件头
builder.AppendLine(GeneratorConstants.AutoGeneratedHeader);
// 添加 using
builder.AddUsings(
"System",
"System.Collections.Generic",
"Fantasy.Assembly",
"Fantasy.DataStructure.Collection",
"Fantasy.Event"
);
builder.AppendLine();
// 开始命名空间(固定使用 Fantasy.Generated
builder.BeginNamespace("Fantasy.Generated");
// 开始类定义(实现 IEventSystemRegistrar 接口)
builder.AddXmlComment($"Auto-generated Event System registration class for {assemblyName}");
builder.BeginClass("EventSystemRegistrar", "internal sealed", "IEventSystemRegistrar");
// 生成字段用于存储已注册的事件处理器(用于 UnRegister
GenerateFields(builder, eventSystems);
// 生成 RegisterSystems 方法
GenerateRegisterMethod(builder, eventSystems);
// 生成 UnRegisterSystems 方法
GenerateUnRegisterMethod(builder, eventSystems);
// 生成 Dispose 方法
GenerateDisposeMethod(builder, eventSystems);
// 结束类和命名空间
builder.EndClass();
builder.EndNamespace();
// 输出源代码
context.AddSource("EventSystemRegistrar.g.cs", builder.ToString());
}
/// <summary>
/// 生成字段,用于存储已注册的事件处理器实例
/// </summary>
private static void GenerateFields(SourceCodeBuilder builder, List<EventSystemTypeInfo> eventSystems)
{
builder.AddComment("Store registered event handlers for UnRegister");
if (!eventSystems.Any())
{
return;
}
foreach (var eventSystemTypeInfo in eventSystems)
{
var fieldName = $"_{eventSystemTypeInfo.TypeName.ToCamelCase()}";
builder.AppendLine($"private {eventSystemTypeInfo.TypeFullName} {fieldName} = new {eventSystemTypeInfo.TypeFullName}();");
}
builder.AppendLine();
}
/// <summary>
/// 生成 RegisterSystems 方法
/// </summary>
private static void GenerateRegisterMethod(SourceCodeBuilder builder, List<EventSystemTypeInfo> eventSystems)
{
builder.AddXmlComment("Register all Event Systems to the containers");
builder.BeginMethod(
"public void RegisterSystems(" +
"OneToManyList<RuntimeTypeHandle, IEvent> events, " +
"OneToManyList<RuntimeTypeHandle, IEvent> asyncEvents, " +
"OneToManyList<RuntimeTypeHandle, IEvent> sphereEvents)");
if (eventSystems.Any())
{
foreach (var eventSystemTypeInfo in eventSystems)
{
var fieldName = $"_{eventSystemTypeInfo.TypeName.ToCamelCase()}";
switch (eventSystemTypeInfo.EventSystemType)
{
case EventSystemType.EventSystem:
{
builder.AppendLine($"events.Add({fieldName}.EventType().TypeHandle, {fieldName});");
continue;
}
case EventSystemType.AsyncEventSystem:
{
builder.AppendLine($"asyncEvents.Add({fieldName}.EventType().TypeHandle, {fieldName});");
continue;
}
case EventSystemType.SphereEventSystem:
{
builder.AppendLine($"sphereEvents.Add({fieldName}.EventType().TypeHandle, {fieldName});");
continue;
}
}
}
}
builder.EndMethod();
builder.AppendLine();
}
/// <summary>
/// 生成 UnRegisterSystems 方法
/// </summary>
private static void GenerateUnRegisterMethod(SourceCodeBuilder builder, List<EventSystemTypeInfo> eventSystems)
{
builder.AddXmlComment("Unregister all Event Systems from the containers (called on hot reload)");
builder.BeginMethod(
"public void UnRegisterSystems(" +
"OneToManyList<RuntimeTypeHandle, IEvent> events, " +
"OneToManyList<RuntimeTypeHandle, IEvent> asyncEvents, " +
"OneToManyList<RuntimeTypeHandle, IEvent> sphereEvents)");
if (eventSystems.Any())
{
foreach (var eventSystemTypeInfo in eventSystems)
{
var fieldName = $"_{eventSystemTypeInfo.TypeName.ToCamelCase()}";
switch (eventSystemTypeInfo.EventSystemType)
{
case EventSystemType.EventSystem:
{
builder.AppendLine($"events.RemoveValue({fieldName}.EventType().TypeHandle, {fieldName});");
continue;
}
case EventSystemType.AsyncEventSystem:
{
builder.AppendLine($"asyncEvents.RemoveValue({fieldName}.EventType().TypeHandle, {fieldName});");
continue;
}
case EventSystemType.SphereEventSystem:
{
builder.AppendLine($"sphereEvents.RemoveValue({fieldName}.EventType().TypeHandle, {fieldName});");
continue;
}
}
}
}
builder.EndMethod();
builder.AppendLine();
}
/// <summary>
/// 生成 Dispose 方法
/// </summary>
private static void GenerateDisposeMethod(SourceCodeBuilder builder, List<EventSystemTypeInfo> eventSystems)
{
builder.AddXmlComment("Dispose all resources");
builder.BeginMethod("public void Dispose()");
builder.AddComment("Clear all references");
if (eventSystems.Any())
{
foreach (var eventSystemTypeInfo in eventSystems)
{
var fieldName = $"_{eventSystemTypeInfo.TypeName.ToCamelCase()}";
builder.AppendLine($"{fieldName} = null;");
}
}
builder.EndMethod();
}
/// <summary>
/// 快速判断语法节点是否可能是 EventSystem 类
/// </summary>
private static bool IsEventSystemClass(SyntaxNode node)
{
if (node is not ClassDeclarationSyntax classDecl)
{
return false;
}
// 必须有基类型列表(继承抽象类)
if (classDecl.BaseList == null || classDecl.BaseList.Types.Count == 0)
{
return false;
}
// 快速检查是否包含可能的 EventSystem 基类名称
var baseListText = classDecl.BaseList.ToString();
return baseListText.Contains("AwakeSystem") ||
baseListText.Contains("AsyncEventSystem") ||
baseListText.Contains("SphereEventSystem");
}
private enum EventSystemType
{
None,
EventSystem, // EventSystem<T> 事件类
AsyncEventSystem, // AsyncEventSystem<T> 事件类
SphereEventSystem, // SphereEventSystem<T> 事件类
}
private sealed class EventSystemTypeInfo
{
public readonly EventSystemType EventSystemType;
public readonly string TypeFullName;
public readonly string TypeName;
private EventSystemTypeInfo(EventSystemType eventSystemType, string typeFullName, string typeName)
{
EventSystemType = eventSystemType;
TypeFullName = typeFullName;
TypeName = typeName;
}
public static EventSystemTypeInfo Create(EventSystemType eventSystemType, INamedTypeSymbol symbol)
{
return new EventSystemTypeInfo(
eventSystemType,
symbol.GetFullName(),
symbol.Name);
}
}
}
}

View File

@@ -0,0 +1,379 @@
using Fantasy.SourceGenerator.Common;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace Fantasy.SourceGenerator.Generators
{
[Generator]
public sealed class MessageHandlerGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 查找所有实现了消息相关接口的类
var messageTypes = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: static (node, _) => IsMessageHandlerClass(node),
transform: static (ctx, _) => GetMessageTypeInfo(ctx))
.Where(static info => info != null)
.Collect();
// 组合编译信息和找到的类型
var compilationAndTypes = context.CompilationProvider.Combine(messageTypes);
// 注册源代码输出
context.RegisterSourceOutput(compilationAndTypes, static (spc, source) =>
{
// 检查1: 是否定义了 FANTASY_NET 或 FANTASY_UNITY 预编译符号
if (!CompilationHelper.HasFantasyDefine(source.Left))
{
return;
}
// 检查2: 是否引用了 Fantasy 框架的核心类型
if (source.Left.GetTypeByMetadataName("Fantasy.Assembly.INetworkProtocolRegistrar") == null)
{
return;
}
GenerateRegistrationCode(spc, source.Left, source.Right!);
});
}
private static void GenerateRegistrationCode(
SourceProductionContext context,
Compilation compilation,
IEnumerable<MessageHandlerInfo> messageHandlerInfos)
{
var messageHandlers = new List<MessageHandlerInfo>();
var routeMessageHandlers = new List<MessageHandlerInfo>();
foreach (var messageHandlerInfo in messageHandlerInfos)
{
switch (messageHandlerInfo.HandlerType)
{
case HandlerType.MessageHandler:
{
messageHandlers.Add(messageHandlerInfo);
break;
}
case HandlerType.RouteMessageHandler:
{
routeMessageHandlers.Add(messageHandlerInfo);
break;
}
}
}
var assemblyName = compilation.AssemblyName ?? "Unknown";
var builder = new SourceCodeBuilder();
builder.AppendLine(GeneratorConstants.AutoGeneratedHeader);
builder.AddUsings(
"System",
"System.Collections.Generic",
"Fantasy.Assembly",
"Fantasy.DataStructure.Dictionary",
"Fantasy.Network.Interface",
"Fantasy.Network",
"Fantasy.Entitas",
"Fantasy.Async",
"System.Runtime.CompilerServices"
);
builder.AppendLine();
builder.BeginNamespace("Fantasy.Generated");
builder.AddXmlComment($"Auto-generated message handler registration class for {assemblyName}");
builder.BeginClass("MessageHandlerResolverRegistrar", "internal sealed", "IMessageHandlerResolver");
// 生成字段用于存储已注册的实例(用于 UnRegister
GenerateFields(builder, messageHandlers, routeMessageHandlers);
// 生成 Register 方法
GenerateRegistrationCode(builder, messageHandlers, routeMessageHandlers);
// 结束类和命名空间
builder.EndClass();
builder.EndNamespace();
// 输出源代码
context.AddSource("MessageHandlerResolverRegistrar.g.cs", builder.ToString());
}
private static void GenerateFields(SourceCodeBuilder builder, List<MessageHandlerInfo> messageHandlers, List<MessageHandlerInfo> routeMessageHandlers)
{
foreach (var messageHandlerInfo in messageHandlers)
{
builder.AppendLine($"private Func<Session, uint, uint, object, FTask> message_{messageHandlerInfo.TypeName} = new {messageHandlerInfo.TypeFullName}().Handle;");
}
foreach (var messageHandlerInfo in routeMessageHandlers)
{
builder.AppendLine($"private Func<Session, Entity, uint, object, FTask> routeMessage_{messageHandlerInfo.TypeName} = new {messageHandlerInfo.TypeFullName}().Handle;");
}
builder.AppendLine();
}
private static void GenerateRegistrationCode(SourceCodeBuilder builder, List<MessageHandlerInfo> messageHandlers, List<MessageHandlerInfo> routeMessageHandlers)
{
builder.AppendLine("[MethodImpl(MethodImplOptions.AggressiveInlining)]");
builder.BeginMethod("public int GetMessageHandlerCount()");
builder.AppendLine($"return {messageHandlers.Count};");
builder.EndMethod();
builder.AppendLine("[MethodImpl(MethodImplOptions.AggressiveInlining)]");
builder.BeginMethod("public int GetRouteMessageHandlerCount()");
builder.AppendLine($"return {routeMessageHandlers.Count};");
builder.EndMethod();
builder.AppendLine("[MethodImpl(MethodImplOptions.AggressiveInlining)]");
builder.BeginMethod("public bool MessageHandler(Session session, uint rpcId, uint protocolCode, object message)");
if (messageHandlers.Any())
{
builder.AppendLine("switch (protocolCode)");
builder.AppendLine("{");
builder.Indent();
foreach (var messageHandlerInfo in messageHandlers)
{
builder.AppendLine($"case {messageHandlerInfo.OpCode}:");
builder.AppendLine("{");
builder.Indent();
builder.AppendLine($"message_{messageHandlerInfo.TypeName}(session, rpcId, protocolCode, message).Coroutine();");
builder.AppendLine($"return true;");
builder.Unindent();
builder.AppendLine("}");
}
builder.AppendLine("default:");
builder.AppendLine("{");
builder.Indent();
builder.AppendLine($"return false;");
builder.Unindent();
builder.AppendLine("}");
builder.Unindent();
builder.AppendLine("}");
}
else
{
builder.AppendLine($"return false;");
}
builder.EndMethod();
builder.AppendLine("#if FANTASY_NET", false);
builder.AppendLine("[MethodImpl(MethodImplOptions.AggressiveInlining)]");
builder.BeginMethod("public async FTask<bool> RouteMessageHandler(Session session, Entity entity, uint rpcId, uint protocolCode, object message)");
if (routeMessageHandlers.Any())
{
builder.AppendLine("switch (protocolCode)");
builder.AppendLine("{");
builder.Indent();
foreach (var routeMessageHandler in routeMessageHandlers)
{
builder.AppendLine($"case {routeMessageHandler.OpCode}:");
builder.AppendLine("{");
builder.Indent();
builder.AppendLine($"await routeMessage_{routeMessageHandler.TypeName}(session, entity, rpcId, message);");
builder.AppendLine($"return true;");
builder.Unindent();
builder.AppendLine("}");
}
builder.AppendLine("default:");
builder.AppendLine("{");
builder.Indent();
builder.AppendLine($"await FTask.CompletedTask;");
builder.AppendLine($"return false;");
builder.Unindent();
builder.AppendLine("}");
builder.Unindent();
builder.AppendLine("}");
}
else
{
builder.AppendLine($"await FTask.CompletedTask;");
builder.AppendLine($"return false;");
}
builder.EndMethod();
builder.AppendLine("#endif", false);
}
private static bool IsMessageHandlerClass(SyntaxNode node)
{
if (node is not ClassDeclarationSyntax classDecl)
{
return false;
}
if (classDecl.BaseList == null || !classDecl.BaseList.Types.Any())
{
return false;
}
foreach (var baseType in classDecl.BaseList.Types)
{
var typeName = baseType.Type.ToString();
if (typeName.Contains("IMessageHandler") ||
typeName.Contains("IRouteMessageHandler") ||
typeName.Contains("Message<") ||
typeName.Contains("MessageRPC<") ||
typeName.Contains("Route<") ||
typeName.Contains("RouteRPC<") ||
typeName.Contains("Addressable<") ||
typeName.Contains("AddressableRPC<") ||
typeName.Contains("Roaming<") ||
typeName.Contains("RoamingRPC<"))
{
return true;
}
}
return false;
}
private static MessageHandlerInfo? GetMessageTypeInfo(GeneratorSyntaxContext context)
{
var classDecl = (ClassDeclarationSyntax)context.Node;
if (context.SemanticModel.GetDeclaredSymbol(classDecl) is not INamedTypeSymbol symbol ||
!symbol.IsInstantiable())
{
return null;
}
var baseType = symbol.BaseType;
if (baseType is not { IsGenericType: true } || baseType.TypeArguments.Length <= 0)
{
return null;
}
var baseTypeName = baseType.OriginalDefinition.ToDisplayString();
switch (baseTypeName)
{
case "Fantasy.Network.Interface.Message<T>":
case "Fantasy.Network.Interface.MessageRPC<TRequest, TResponse>":
{
return new MessageHandlerInfo(
HandlerType.MessageHandler,
symbol.GetFullName(),
symbol.Name,
GetOpCode(context, baseType, 0));
}
case "Fantasy.Network.Interface.Route<TEntity, TMessage>":
case "Fantasy.Network.Interface.RouteRPC<TEntity, TRouteRequest, TRouteResponse>":
case "Fantasy.Network.Interface.Addressable<TEntity, TMessage>":
case "Fantasy.Network.Interface.AddressableRPC<TEntity, TRouteRequest, TRouteResponse>":
case "Fantasy.Network.Interface.Roaming<TEntity, TMessage>":
case "Fantasy.Network.Interface.RoamingRPC<TEntity, TRouteRequest, TRouteResponse>":
{
return new MessageHandlerInfo(
HandlerType.RouteMessageHandler,
symbol.GetFullName(),
symbol.Name,
GetOpCode(context, baseType, 1));
}
}
return null;
}
private static uint? GetOpCode(GeneratorSyntaxContext context, INamedTypeSymbol baseType, int index)
{
if (baseType.TypeArguments.Length <= index)
{
return null;
}
var messageType = (INamedTypeSymbol)baseType.TypeArguments[index];
var messageName = messageType.Name;
var compilation = context.SemanticModel.Compilation;
// 策略1从消息类型所在程序集中搜索 OpCode 类
var messageAssembly = messageType.ContainingAssembly;
var namespaceName = messageType.ContainingNamespace.ToDisplayString();
// 遍历程序集中的所有类型,查找 OuterOpcode 或 InnerOpcode
var opCodeTypeNames = new[] { "OuterOpcode", "InnerOpcode" };
foreach (var opCodeTypeName in opCodeTypeNames)
{
var opCodeType = FindTypeInAssembly(messageAssembly.GlobalNamespace, namespaceName, opCodeTypeName);
if (opCodeType != null)
{
var opCodeField = opCodeType.GetMembers(messageName).OfType<IFieldSymbol>().FirstOrDefault();
if (opCodeField != null && opCodeField.IsConst && opCodeField.ConstantValue is uint constValue)
{
return constValue;
}
}
}
// 策略2如果策略1失败尝试从 OpCode() 方法的语法树中解析(仅适用于同项目中的消息)
var opCodeMethod = messageType.GetMembers("OpCode").OfType<IMethodSymbol>().FirstOrDefault();
if (opCodeMethod != null)
{
var opCodeSyntax = opCodeMethod.DeclaringSyntaxReferences.FirstOrDefault()?.GetSyntax() as MethodDeclarationSyntax;
if (opCodeSyntax?.Body != null)
{
var returnStatement = opCodeSyntax.Body.DescendantNodes()
.OfType<ReturnStatementSyntax>()
.FirstOrDefault();
if (returnStatement?.Expression != null)
{
var syntaxTree = opCodeSyntax.SyntaxTree;
if (compilation.ContainsSyntaxTree(syntaxTree))
{
var semanticModel = compilation.GetSemanticModel(syntaxTree);
// 尝试符号解析
var symbolInfo = semanticModel.GetSymbolInfo(returnStatement.Expression);
if (symbolInfo.Symbol is IFieldSymbol fieldSymbol && fieldSymbol.IsConst && fieldSymbol.ConstantValue is uint constValue2)
{
return constValue2;
}
// 尝试常量值解析
var constantValue = semanticModel.GetConstantValue(returnStatement.Expression);
if (constantValue.HasValue && constantValue.Value is uint uintValue)
{
return uintValue;
}
}
}
}
}
return null;
}
// 辅助方法:在程序集的命名空间中递归查找指定类型
private static INamedTypeSymbol? FindTypeInAssembly(INamespaceSymbol namespaceSymbol, string targetNamespace, string typeName)
{
// 如果当前命名空间匹配目标命名空间,查找类型
if (namespaceSymbol.ToDisplayString() == targetNamespace)
{
var type = namespaceSymbol.GetTypeMembers(typeName).FirstOrDefault();
if (type != null)
{
return type;
}
}
// 递归搜索子命名空间
foreach (var childNamespace in namespaceSymbol.GetNamespaceMembers())
{
var result = FindTypeInAssembly(childNamespace, targetNamespace, typeName);
if (result != null)
{
return result;
}
}
return null;
}
private enum HandlerType
{
None,
MessageHandler,
RouteMessageHandler
}
private sealed record MessageHandlerInfo(
HandlerType HandlerType,
string TypeFullName,
string TypeName,
uint? OpCode);
}
}

View File

@@ -0,0 +1,398 @@
using System.Linq;
using System.Text;
using Fantasy.SourceGenerator.Common;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
namespace Fantasy.SourceGenerator.Generators;
[Generator]
internal partial class NetworkProtocolGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var networkProtocols = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: static (node, _) => IsNetworkProtocolClass(node),
transform: static (ctx, _) => GetNetworkProtocolInfo(ctx))
.Where(static info => info != null)
.Collect();
var compilationAndTypes = context.CompilationProvider.Combine(networkProtocols);
context.RegisterSourceOutput(compilationAndTypes, static (spc, source) =>
{
if (!CompilationHelper.HasFantasyDefine(source.Left))
{
return;
}
if (source.Left.GetTypeByMetadataName("Fantasy.Assembly.INetworkProtocolRegistrar") == null)
{
return;
}
GenerateCode(spc, source.Left, source.Right!);
});
}
#region GenerateCode
private static void GenerateCode(
SourceProductionContext context,
Compilation compilation,
IEnumerable<NetworkProtocolTypeInfo> networkProtocolTypeInfos)
{
var networkProtocolTypeInfoList = networkProtocolTypeInfos.ToList();
// 获取当前程序集名称(仅用于注释)
var assemblyName = compilation.AssemblyName ?? "Unknown";
// 生成网络网络协议类型注册的类。
GenerateNetworkProtocolTypesCode(context, assemblyName, networkProtocolTypeInfoList);
// 生成OpCode辅助方法。
GenerateNetworkProtocolOpCodeResolverCode(context, assemblyName, networkProtocolTypeInfoList);
// 生成Request消息的ResponseType辅助方法。
GenerateNetworkProtocolResponseTypesResolverCode(context, assemblyName, networkProtocolTypeInfoList);
}
private static void GenerateNetworkProtocolTypesCode(
SourceProductionContext context,
string assemblyName,
List<NetworkProtocolTypeInfo> networkProtocolTypeInfoList)
{
var builder = new SourceCodeBuilder();
// 添加文件头
builder.AppendLine(GeneratorConstants.AutoGeneratedHeader);
// 添加 using
builder.AddUsings(
"System",
"System.Collections.Generic",
"Fantasy.Assembly",
"Fantasy.DataStructure.Collection"
);
// 开始命名空间(固定使用 Fantasy.Generated
builder.BeginNamespace("Fantasy.Generated");
// 开始类定义(实现 IEventSystemRegistrar 接口)
builder.AddXmlComment($"Auto-generated NetworkProtocol registration class for {assemblyName}");
builder.BeginClass("NetworkProtocolRegistrar", "internal sealed", "INetworkProtocolRegistrar");
builder.BeginMethod("public List<Type> GetNetworkProtocolTypes()");
if (networkProtocolTypeInfoList.Any())
{
builder.AppendLine($"return new List<Type>({networkProtocolTypeInfoList.Count})");
builder.AppendLine("{");
builder.Indent();
foreach (var system in networkProtocolTypeInfoList)
{
builder.AppendLine($"typeof({system.FullName}),");
}
builder.Unindent();
builder.AppendLine("};");
builder.AppendLine();
}
else
{
builder.AppendLine($"return new List<Type>();");
}
builder.EndMethod();
builder.AppendLine();
// 结束类和命名空间
builder.EndClass();
builder.EndNamespace();
// 输出源代码
context.AddSource("NetworkProtocolRegistrar.g.cs", builder.ToString());
}
private static void GenerateNetworkProtocolOpCodeResolverCode(
SourceProductionContext context,
string assemblyName,
List<NetworkProtocolTypeInfo> networkProtocolTypeInfoList)
{
var routeTypeInfos = networkProtocolTypeInfoList.Where(d => d.RouteType.HasValue).ToList();
var builder = new SourceCodeBuilder();
// 添加文件头
builder.AppendLine(GeneratorConstants.AutoGeneratedHeader);
// 添加 using
builder.AddUsings(
"System",
"System.Collections.Generic",
"Fantasy.Assembly",
"Fantasy.DataStructure.Collection",
"System.Runtime.CompilerServices"
);
builder.AppendLine();
// 开始命名空间(固定使用 Fantasy.Generated
builder.BeginNamespace("Fantasy.Generated");
// 开始类定义(实现 INetworkProtocolOpCodeResolver 接口)
builder.AddXmlComment($"Auto-generated NetworkProtocolOpCodeResolverRegistrar class for {assemblyName}");
builder.BeginClass("NetworkProtocolOpCodeResolverRegistrar", "internal sealed", "INetworkProtocolOpCodeResolver");
builder.AddXmlComment($"GetOpCodeCount");
builder.AppendLine("[MethodImpl(MethodImplOptions.AggressiveInlining)]");
builder.BeginMethod("public int GetOpCodeCount()");
builder.AppendLine($"return {networkProtocolTypeInfoList.Count};");
builder.EndMethod();
builder.AddXmlComment($"GetCustomRouteTypeCount");
builder.AppendLine("[MethodImpl(MethodImplOptions.AggressiveInlining)]");
builder.BeginMethod("public int GetCustomRouteTypeCount()");
builder.AppendLine($"return {routeTypeInfos.Count};");
builder.EndMethod();
// 开始定义GetOpCodeType方法
builder.AddXmlComment($"GetOpCodeType");
builder.AppendLine("[MethodImpl(MethodImplOptions.AggressiveInlining)]");
builder.BeginMethod("public Type GetOpCodeType(uint opCode)");
if (networkProtocolTypeInfoList.Any())
{
builder.AppendLine("switch (opCode)");
builder.AppendLine("{");
builder.Indent();
foreach (var networkProtocolTypeInfo in networkProtocolTypeInfoList)
{
builder.AppendLine($"case {networkProtocolTypeInfo.OpCode}:");
builder.AppendLine("{");
builder.Indent();
builder.AppendLine($"return typeof({networkProtocolTypeInfo.FullName});");
builder.Unindent();
builder.AppendLine("}");
}
builder.AppendLine("default:");
builder.AppendLine("{");
builder.Indent();
builder.AppendLine($"return null!;");
builder.Unindent();
builder.AppendLine("}");
builder.Unindent();
builder.AppendLine("}");
builder.AppendLine();
}
else
{
builder.AppendLine($"return null!;");
}
builder.EndMethod();
// 开始定义GetRouteType方法
builder.AddXmlComment($"CustomRouteType");
builder.AppendLine("[MethodImpl(MethodImplOptions.AggressiveInlining)]");
builder.BeginMethod("public int? GetCustomRouteType(uint opCode)");
if (routeTypeInfos.Any())
{
builder.AppendLine("switch (opCode)");
builder.AppendLine("{");
builder.Indent();
foreach (var routeTypeInfo in routeTypeInfos)
{
builder.AppendLine($"case {routeTypeInfo.OpCode}:");
builder.AppendLine("{");
builder.Indent();
builder.AppendLine($"return {routeTypeInfo.RouteType};");
builder.Unindent();
builder.AppendLine("}");
}
builder.AppendLine("default:");
builder.AppendLine("{");
builder.Indent();
builder.AppendLine($"return null;");
builder.Unindent();
builder.AppendLine("}");
builder.Unindent();
builder.AppendLine("}");
builder.AppendLine();
}
else
{
builder.AppendLine($"return null;");
}
builder.EndMethod();
builder.AppendLine();
// 结束类和命名空间
builder.EndClass();
builder.EndNamespace();
// 输出源代码
context.AddSource("NetworkProtocolOpCodeResolverRegistrar.g.cs", builder.ToString());
}
private static void GenerateNetworkProtocolResponseTypesResolverCode(
SourceProductionContext context,
string assemblyName,
List<NetworkProtocolTypeInfo> networkProtocolTypeInfoList)
{
var requestList = networkProtocolTypeInfoList.Where(d => d.ResponseType != null).ToList();
var builder = new SourceCodeBuilder();
// 添加文件头
builder.AppendLine(GeneratorConstants.AutoGeneratedHeader);
// 添加 using
builder.AddUsings(
"System",
"System.Collections.Generic",
"Fantasy.Assembly",
"Fantasy.DataStructure.Collection",
"System.Runtime.CompilerServices"
);
builder.AppendLine();
// 开始命名空间(固定使用 Fantasy.Generated
builder.BeginNamespace("Fantasy.Generated");
// 开始类定义(实现 IEventSystemRegistrar 接口)
builder.AddXmlComment($"Auto-generated NetworkProtocolResponseTypeResolverRegistrar class for {assemblyName}");
builder.BeginClass("NetworkProtocolResponseTypeResolverRegistrar", "internal sealed", "INetworkProtocolResponseTypeResolver");
builder.AddXmlComment($"GetOpCodeCount");
builder.AppendLine("[MethodImpl(MethodImplOptions.AggressiveInlining)]");
builder.BeginMethod("public int GetRequestCount()");
builder.AppendLine($"return {requestList.Count};");
builder.EndMethod();
// 开始定义GetOpCodeType方法
builder.AddXmlComment($"GetOpCodeType");
builder.AppendLine("[MethodImpl(MethodImplOptions.AggressiveInlining)]");
builder.BeginMethod("public Type GetResponseType(uint opCode)");
if (requestList.Any())
{
builder.AppendLine("switch (opCode)");
builder.AppendLine("{");
builder.Indent();
foreach (var request in requestList)
{
builder.AppendLine($"case {request.OpCode}:");
builder.AppendLine("{");
builder.Indent();
builder.AppendLine($"return typeof({request.ResponseType});");
builder.Unindent();
builder.AppendLine("}");
}
builder.AppendLine("default:");
builder.AppendLine("{");
builder.Indent();
builder.AppendLine($"return null!;");
builder.Unindent();
builder.AppendLine("}");
builder.Unindent();
builder.AppendLine("}");
builder.AppendLine();
}
else
{
builder.AppendLine($"return null!;");
}
builder.EndMethod();
builder.AppendLine();
// 结束类和命名空间
builder.EndClass();
builder.EndNamespace();
// 输出源代码
context.AddSource("NetworkProtocolResponseTypeResolverRegistrar.g.cs", builder.ToString());
}
#endregion
private static NetworkProtocolTypeInfo? GetNetworkProtocolInfo(GeneratorSyntaxContext context)
{
var classDecl = (ClassDeclarationSyntax)context.Node;
var symbol = context.SemanticModel.GetDeclaredSymbol(classDecl) as INamedTypeSymbol;
if (symbol == null || !symbol.IsInstantiable())
{
return null;
}
var baseType = symbol.BaseType;
if (baseType == null)
{
return null;
}
if (baseType.ToDisplayString() != "Fantasy.Network.Interface.AMessage")
{
return null;
}
// 获取 OpCode 方法的值
uint? opCodeValue = null;
var opCodeMethod = symbol.GetMembers("OpCode").OfType<IMethodSymbol>().FirstOrDefault();
var opCodeSyntax = opCodeMethod?.DeclaringSyntaxReferences.FirstOrDefault()?.GetSyntax() as MethodDeclarationSyntax;
if (opCodeSyntax?.Body != null)
{
var returnStatement = opCodeSyntax.Body.DescendantNodes()
.OfType<ReturnStatementSyntax>()
.FirstOrDefault();
if (returnStatement?.Expression != null)
{
var constantValue = context.SemanticModel.GetConstantValue(returnStatement.Expression);
if (constantValue.HasValue && constantValue.Value is uint uintValue)
{
opCodeValue = uintValue;
}
}
}
if (!opCodeValue.HasValue)
{
return null;
}
// 获取 ResponseType 属性及其类型
string? responseTypeName = null;
var responseTypeProperty = symbol.GetMembers("ResponseType").OfType<IPropertySymbol>().FirstOrDefault();
if (responseTypeProperty != null)
{
// 获取 ResponseType 属性的类型(例如 G2C_TestResponse
responseTypeName = responseTypeProperty.Type.GetFullName();
}
// 获取 RouteType 属性的值
int? routeTypeValue = null;
var routeTypeProperty = symbol.GetMembers("RouteType").OfType<IPropertySymbol>().FirstOrDefault();
var routeTypeSyntax = routeTypeProperty?.DeclaringSyntaxReferences.FirstOrDefault()?.GetSyntax() as PropertyDeclarationSyntax;
if (routeTypeSyntax?.ExpressionBody != null)
{
var constantValue = context.SemanticModel.GetConstantValue(routeTypeSyntax.ExpressionBody.Expression);
if (constantValue.HasValue && constantValue.Value is int intValue)
{
routeTypeValue = intValue;
}
}
return new NetworkProtocolTypeInfo(
symbol.GetFullName(),
opCodeValue.Value,
responseTypeName,
routeTypeValue
);
}
private static bool IsNetworkProtocolClass(SyntaxNode node)
{
if (node is not ClassDeclarationSyntax classDecl)
{
return false;
}
if (classDecl.BaseList == null)
{
return false;
}
foreach (var baseTypeSyntax in classDecl.BaseList.Types)
{
if (baseTypeSyntax.Type.ToString().Contains("AMessage"))
{
return true;
}
}
return false;
}
private sealed record NetworkProtocolTypeInfo(
string FullName,
uint OpCode,
string? ResponseType,
int? RouteType);
}

View File

@@ -0,0 +1,267 @@
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
{
/// <summary>
/// SeparateTable 接口生成器
/// 自动生成 SeparateTable 所需的注册代码,替代运行时反射
/// </summary>
[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<string, string>();
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<SeparateTableTypeInfo> 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<T>(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<T>(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<SeparateTableTypeInfo> separateTableTypeInfoList)
{
SeparateTableInfo.AppendLine("private readonly List<ISeparateTableRegistrar.SeparateTableInfo> _separateTableInfos = new List<ISeparateTableRegistrar.SeparateTableInfo>()");
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<SeparateTableTypeInfo> separateTableTypeInfos)
{
builder.BeginMethod("public List<ISeparateTableRegistrar.SeparateTableInfo> Register()");
builder.AppendLine("return _separateTableInfos;");
builder.EndMethod();
builder.AppendLine();
}
private static void GenerateUnRegisterMethod(SourceCodeBuilder builder, List<SeparateTableTypeInfo> separateTableTypeInfos)
{
builder.BeginMethod("public List<ISeparateTableRegistrar.SeparateTableInfo> 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<string, string> SeparateTableInfo;
public readonly string TypeFullName;
public readonly string TypeName;
private SeparateTableTypeInfo(string typeFullName, string typeName,
Dictionary<string, string> separateTableInfo)
{
TypeFullName = typeFullName;
TypeName = typeName;
SeparateTableInfo = separateTableInfo;
}
public static SeparateTableTypeInfo Create(INamedTypeSymbol symbol,
Dictionary<string, string> separateTableInfo)
{
return new SeparateTableTypeInfo(
symbol.GetFullName(),
symbol.Name,
separateTableInfo);
}
}
}
}

View File

@@ -0,0 +1,373 @@
# Fantasy.SourceGenerator
Fantasy 框架的增量源代码生成器Incremental Source Generator在编译时自动生成注册代码消除反射开销提升性能并支持 Native AOT。
## 功能特性
### ✅ 已实现的生成器
- **AssemblyInitializerGenerator**: 自动生成程序集初始化器ModuleInitializer在程序集加载时自动注册到框架
- **EntitySystemGenerator**: 自动生成 Entity SystemAwake/Update/Destroy/Deserialize/LateUpdate注册代码
- **EventSystemGenerator**: 自动生成 Event SystemEventSystem/AsyncEventSystem/SphereEventSystem注册代码
- **MessageDispatcherGenerator**: 自动生成消息调度器(网络协议、消息处理器、路由处理器)注册代码
- **EntityTypeCollectionGenerator**: 自动生成 Entity 类型集合,用于框架类型管理
- **ProtoBufGenerator**: 自动生成 ProtoBuf 类型注册代码,用于序列化系统
## 使用方法
### 自动集成(推荐)
Framework 已经完全集成了 Source Generator开发者**无需手动配置**。
#### 工作流程
1. **编译时自动生成**: 当你构建项目时Source Generator 会自动扫描代码并生成注册器
2. **自动注册**: `AssemblyInitializerGenerator` 生成的 `ModuleInitializer` 会在程序集加载时自动注册所有生成器到框架
3. **透明运行**: 框架内部自动使用生成的注册器,无需任何手动调用
#### 示例:添加一个 Entity System
```csharp
// 只需按照 Fantasy 框架的规范编写代码
public class MyEntityAwakeSystem : AwakeSystem<MyEntity>
{
protected override void Awake(MyEntity self)
{
// 你的逻辑
}
}
```
编译后Source Generator 会自动:
- 生成 `EntitySystemRegistrar.g.cs` 包含此 System
- 在程序集加载时自动注册到框架
- 无需任何额外步骤
### 手动集成(高级用途)
如果你需要在自己的项目中引用 Source Generator
```xml
<ItemGroup>
<ProjectReference Include="..\Fantasy.SourceGenerator\Fantasy.SourceGenerator.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
</ItemGroup>
```
确保项目定义了 `FANTASY_NET``FANTASY_UNITY` 预编译符号:
```xml
<PropertyGroup>
<DefineConstants>FANTASY_NET</DefineConstants>
</PropertyGroup>
```
## 生成的代码示例
Source Generator 会在 `obj/.../generated/Fantasy.SourceGenerator/` 目录下自动生成多个注册器类:
### AssemblyInitializer.g.cs核心
```csharp
// 程序集初始化器 - 在程序集加载时自动执行
namespace Fantasy.Generated
{
internal static class AssemblyInitializer
{
[ModuleInitializer] // .NET 使用 ModuleInitializer
// [RuntimeInitializeOnLoadMethod] // Unity 使用此属性
internal static void Initialize()
{
var assembly = typeof(AssemblyInitializer).Assembly;
var assemblyManifestId = HashCodeHelper.ComputeHash64(assembly.GetName().Name);
// 创建所有生成的注册器
var protoBufRegistrar = new Fantasy.Generated.ProtoBufRegistrar();
var eventSystemRegistrar = new Fantasy.Generated.EventSystemRegistrar();
var entitySystemRegistrar = new Fantasy.Generated.EntitySystemRegistrar();
var messageDispatcherRegistrar = new Fantasy.Generated.MessageDispatcherRegistrar();
var entityTypeCollectionRegistrar = new Fantasy.Generated.EntityTypeCollectionRegistrar();
// 一次性注册到框架
Fantasy.Assembly.AssemblyManifest.Register(
assemblyManifestId,
assembly,
protoBufRegistrar,
eventSystemRegistrar,
entitySystemRegistrar,
messageDispatcherRegistrar,
entityTypeCollectionRegistrar);
}
}
// 用于强制加载程序集的标记类
public static class MyAssembly_AssemblyMarker
{
public static void EnsureLoaded() { }
}
}
```
### EntitySystemRegistrar.g.cs
```csharp
namespace Fantasy.Generated
{
internal sealed class EntitySystemRegistrar : IEntitySystemRegistrar
{
public void RegisterSystems(
Dictionary<Type, IAwakeSystem> awakeSystems,
Dictionary<Type, IUpdateSystem> updateSystems,
// ... 其他系统类型
)
{
awakeSystems.Add(typeof(MyEntity), new MyEntityAwakeSystem());
updateSystems.Add(typeof(MyEntity), new MyEntityUpdateSystem());
// ... 自动注册所有发现的 System
}
}
}
```
### EventSystemRegistrar.g.cs
```csharp
namespace Fantasy.Generated
{
internal sealed class EventSystemRegistrar : IEventSystemRegistrar
{
private MyEventHandler _myEventHandler = new MyEventHandler();
public void RegisterSystems(
OneToManyList<Type, IEvent> events,
OneToManyList<Type, IEvent> asyncEvents,
OneToManyList<Type, IEvent> sphereEvents)
{
events.Add(_myEventHandler.EventType(), _myEventHandler);
}
}
}
```
### MessageDispatcherRegistrar.g.cs
```csharp
namespace Fantasy.Generated
{
internal sealed class MessageDispatcherRegistrar : IMessageDispatcherRegistrar
{
public void RegisterSystems(
DoubleMapDictionary<uint, Type> networkProtocols,
Dictionary<Type, Type> responseTypes,
Dictionary<Type, IMessageHandler> messageHandlers,
// ...
)
{
var c2GLoginRequest = new C2G_LoginRequest();
networkProtocols.Add(c2GLoginRequest.OpCode(), typeof(C2G_LoginRequest));
responseTypes.Add(typeof(C2G_LoginRequest), typeof(G2C_LoginResponse));
}
}
}
```
## 性能对比
| 场景 | 反射方式 | Source Generator | 性能提升 |
|------|---------|------------------|---------|
| 程序集加载时注册 | ~50ms100个类型 | ~1ms | **50x** |
| 启动时间 | 受反射影响 | 几乎无影响 | **显著** |
| 运行时实例化 | ~150ns/个 | ~3ns/个 | **50x** |
| 内存分配 | 反射元数据开销 | 无额外开销 | **更优** |
| Native AOT 兼容 | ❌ 不支持 | ✅ 完全支持 | - |
| IL2CPP (Unity) | ⚠️ 性能差 | ✅ 完美支持 | **必需** |
## 调试生成的代码
### 查看生成的代码
生成的代码位于:
```
<项目目录>/obj/<配置>/<目标框架>/generated/Fantasy.SourceGenerator/
```
例如:
```
obj/Debug/net8.0/generated/Fantasy.SourceGenerator/Fantasy.SourceGenerator.Generators.AssemblyInitializerGenerator/AssemblyInitializer.g.cs
obj/Debug/net8.0/generated/Fantasy.SourceGenerator/Fantasy.SourceGenerator.Generators.EntitySystemGenerator/EntitySystemRegistrar.g.cs
```
### IDE 支持
- **Visual Studio**: Dependencies → Analyzers → Fantasy.SourceGenerator → 展开查看生成的文件
- **JetBrains Rider**: Dependencies → Source Generators → Fantasy.SourceGenerator
- **VS Code**: 需要手动浏览 `obj/` 目录
### 启用详细日志
`.csproj` 中添加:
```xml
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)/GeneratedFiles</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
```
这会将生成的文件输出到 `obj/GeneratedFiles/` 目录,方便查看和调试。
## 兼容性
### 平台支持
| 平台 | 状态 | 说明 |
|------|------|------|
| .NET 8.0+ | ✅ 完全支持 | 使用 Roslyn 4.8.0 |
| .NET Framework 4.x | ❌ 不支持 | Source Generator 需要 .NET Standard 2.0+ |
| Unity 2020.2+ | ✅ 完全支持 | 使用 Roslyn 4.0.1(兼容版本) |
| Native AOT | ✅ 完全支持 | 无反射,完美兼容 AOT |
| IL2CPP | ✅ 完全支持 | Unity IL2CPP 必需 |
### 运行模式
- **开发环境**: Source Generator 自动生成,支持热重载(重新编译)
- **生产环境**: Source Generator 自动生成,零反射开销
- **热更新程序集**: 框架会检测可收集的 AssemblyLoadContext支持程序集卸载和重载
## 技术特性
### 增量编译支持
所有生成器都实现了 `IIncrementalGenerator` 接口:
- ✅ 仅在相关代码变化时重新生成
- ✅ 大幅提升编译速度
- ✅ 支持部分代码更新
### 条件编译
生成器会根据预编译符号调整生成代码:
- `FANTASY_NET`: .NET 平台特定功能
- `FANTASY_UNITY`: Unity 平台特定功能
- 自动检测平台并生成对应代码
### 自动清理
- 程序集卸载时自动反注册(支持热更新)
- 实现 `IDisposable` 接口,支持资源释放
- 无内存泄漏风险
## 多版本构建支持
### Unity 版本 vs .NET 版本
此项目支持两种构建配置,使用不同版本的 Roslyn 编译器:
#### Unity 配置(用于 Unity Package
```bash
dotnet build --configuration Unity
```
- **Roslyn 版本**: 4.0.1
- **用途**: Unity 2020.2+ 项目
- **兼容性**: Unity 2020.2 - Unity 2023.x
- **输出**: `bin/Unity/netstandard2.0/Fantasy.SourceGenerator.dll`
#### Release/Debug 配置(用于 .NET 项目)
```bash
dotnet build --configuration Release
```
- **Roslyn 版本**: 4.8.0
- **用途**: .NET 8/9 项目
- **兼容性**: .NET 8.0+
- **输出**: `bin/Release/netstandard2.0/Fantasy.SourceGenerator.dll`
### 为什么需要两个版本?
Unity 使用的 Roslyn 编译器版本较旧Source Generator 引用的 Roslyn 版本必须**小于或等于**运行时编译器版本:
| 平台 | Roslyn 版本 | Source Generator 配置 |
|------|------------|---------------------|
| Unity 2020.2-2021.x | 3.8 - 4.0 | Unity (4.0.1) |
| Unity 2022.x | 4.3 | Unity (4.0.1) |
| Unity 2023.x | 4.6+ | Unity (4.0.1) |
| .NET 8.0 | 4.8+ | Release (4.8.0) |
| .NET 9.0 | 4.10+ | Release (4.8.0) |
### 自动化更新脚本
**更新 Unity Package:**
```bash
# macOS/Linux
./update-unity-source-generator.sh
# Windows
update-unity-source-generator.bat
```
这些脚本会自动使用 Unity 配置构建并更新到 Fantasy.Unity package。在项目的Tools/Update-Unity-Source-Generator下。
### 技术实现
`.csproj` 中使用条件 PackageReference
```xml
<!-- Unity 版本 - Roslyn 4.0.1 -->
<ItemGroup Condition="'$(Configuration)' == 'Unity' OR '$(Configuration)' == 'UnityDebug'">
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" PrivateAssets="all" />
</ItemGroup>
<!-- .NET 版本 - Roslyn 4.8.0 -->
<ItemGroup Condition="'$(Configuration)' != 'Unity' AND '$(Configuration)' != 'UnityDebug'">
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all" />
</ItemGroup>
```
### 故障排查
**CS9057 警告/错误:**
```
warning CS9057: The analyzer assembly references version 'X' of the compiler,
which is newer than the currently running version 'Y'.
```
**解决方案**: 确保使用 Unity 配置构建用于 Unity 的版本。
## 常见问题FAQ
### Q: 为什么看不到生成的代码?
A: 生成的代码在 `obj/` 目录下,需要编译项目后才能看到。可以在 IDE 的 Analyzers/Source Generators 节点中查看。
### Q: 可以禁用某个生成器吗?
A: 生成器会自动检测代码特征,如果你的项目中没有相关类型,对应的生成器不会生成代码。无需手动禁用。
### Q: Source Generator 会影响编译速度吗?
A: 首次编译会扫描所有代码,后续使用增量编译,仅在相关代码变化时重新生成,对编译速度影响很小。
### Q: Unity 项目如何使用?
A: Fantasy.Unity package 已经包含了兼容版本的 Source GeneratorRoslyn 4.0.1),无需额外配置。
### Q: 支持热重载吗?
A: 支持。框架会检测 AssemblyLoadContext 的卸载事件,自动反注册。重新编译后自动注册新版本。
### Q: Native AOT 部署需要注意什么?
A: 无需特别注意Source Generator 生成的代码不使用反射,完全兼容 Native AOT。
## 贡献指南
欢迎贡献代码!如果你想添加新的生成器:
1.`Generators/` 目录下创建新的生成器类
2. 实现 `IIncrementalGenerator` 接口
3.`AssemblyInitializerGenerator` 中添加对应的注册器接口
4. 更新本 README 文档
---
**维护者**: 初见
**更新日期**: 2025-10-19
**版本**: 1.0.0

View File

@@ -0,0 +1,42 @@
# Source Generator 调试指南
## 当前状态
生成器已编译成功,但没有生成任何代码文件。
## 可能的原因
1. **类型匹配问题**:生成器的 `IsSystemClass``GetSystemType` 方法无法正确识别 System 类
2. **Incremental Generator Pipeline 问题**Pipeline 可能过滤掉了所有候选类
3. **命名空间不匹配**:生成器可能在寻找错误的命名空间
## 调试步骤
### 方法 1简化生成器逻辑
`IsSystemClass` 改为返回 `true` 以查看是否有任何类被处理:
```csharp
private static bool IsSystemClass(SyntaxNode node)
{
return node is ClassDeclarationSyntax; // 处理所有类
}
```
### 方法 2查看生成器输出
```bash
# 启用详细日志
dotnet build /p:EmitCompilerGeneratedFiles=true /p:CompilerGeneratedFilesOutputPath=Generated
# 查看生成的文件
ls -la Generated/
```
### 方法 3使用 LinqPad/RoslynPad 测试
创建独立的测试项目来验证 Roslyn API 调用。
## 下一步
建议先尝试方法 2查看 MSBuild 是否能输出生成的文件。