Files
Fishing2Server/Fantasy/Fantasy.Net/Fantasy.SourceGenerator/Generators/EventSystemGenerator.cs
2025-10-29 17:59:43 +08:00

306 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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);
}
}
}
}