306 lines
12 KiB
C#
306 lines
12 KiB
C#
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);
|
||
}
|
||
}
|
||
}
|
||
}
|