框架更新

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,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