框架更新
This commit is contained in:
373
Fantasy/Fantasy.Net/Fantasy.SourceGenerator/README.md
Normal file
373
Fantasy/Fantasy.Net/Fantasy.SourceGenerator/README.md
Normal file
@@ -0,0 +1,373 @@
|
||||
# Fantasy.SourceGenerator
|
||||
|
||||
Fantasy 框架的增量源代码生成器(Incremental Source Generator),在编译时自动生成注册代码,消除反射开销,提升性能并支持 Native AOT。
|
||||
|
||||
## 功能特性
|
||||
|
||||
### ✅ 已实现的生成器
|
||||
|
||||
- **AssemblyInitializerGenerator**: 自动生成程序集初始化器(ModuleInitializer),在程序集加载时自动注册到框架
|
||||
- **EntitySystemGenerator**: 自动生成 Entity System(Awake/Update/Destroy/Deserialize/LateUpdate)注册代码
|
||||
- **EventSystemGenerator**: 自动生成 Event System(EventSystem/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 | 性能提升 |
|
||||
|------|---------|------------------|---------|
|
||||
| 程序集加载时注册 | ~50ms(100个类型) | ~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 Generator(Roslyn 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
|
||||
Reference in New Issue
Block a user