249 lines
6.4 KiB
Markdown
Raw Permalink 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.

# ET Source Generator 分析器规则
源码位置:`My project/Packages/cn.etetet.sourcegenerator/DotNet~/ET.SourceGenerator/Analyzer/`
只对**新写或新改**的代码生效。下面按"踩坑频率从高到低"排序。
---
## ET0004 — Hotfix 程序集禁止非 const 字段(含属性)
**最爱挖坑的一条**。HotfixProjectFieldDeclarationAnalyzer 把所有 **属性** 也当成"非const字段"报错。
```csharp
// ❌ Hotfix 程序集
public abstract class RpcMessageHandler<TReq, TResp> : MessageSessionHandler<TReq, TResp>
{
protected virtual string Module => "Net"; // ET0004: 字段: Module
protected virtual string Action => typeof(TReq).Name; // ET0004: 字段: Action
}
// ❌ Hotfix 程序集
public static class LogExtensions
{
private static readonly object AuditLock = new(); // ET0004 + ET0015
}
// ✅ 修复 1完全去掉属性在 Run 里 inline
public abstract class RpcMessageHandler<TReq, TResp> : MessageSessionHandler<TReq, TResp>
{
protected sealed override async ETTask Run(Session session, TReq request, TResp response)
{
string action = typeof(TReq).Name;
Log.Info($"[Net] {action} in");
await OnRun(session, request, response);
}
protected abstract ETTask OnRun(Session session, TReq req, TResp resp);
}
// ✅ 修复 2挪到 Model + [EnableClass]Model 程序集不被本规则约束
// 文件路径从 Scripts/Hotfix/Share/ 移到 Scripts/Model/Share/
namespace ET
{
[EnableClass]
public static class LogExtensions
{
private static readonly object AuditLock = new(); // ✅ Model 允许
}
}
```
适用程序集:`ET.Hotfix``ET.HotfixView``ET.Hotfix.Test``ET.HotfixView.Test`
---
## ET0002 — Entity 字段访问需 FriendOf
```csharp
public class BagComponent : Entity, IAwake
{
public Dictionary<long, EntityRef<ItemUnit>> ItemMap = new();
}
// ❌ 触发 ET0002
public static class BagService
{
public static bool TryUseItem(Player player, long idx)
{
var bag = player.GetComponent<BagComponent>();
bag.ItemMap.TryGetValue(...); // 错:跨类访问字段
}
}
// ✅
[FriendOf(typeof(BagComponent))]
public static class BagService
{
// ...
}
```
**属性不算字段**`ItemUnit``{ get; set; }` 属性,外部访问无需 FriendOf。
**子类访问父类**字段无需 FriendOf本规则只针对**跨类访问**
**FriendOf 写在使用方类上**,不是被使用的类。
---
## ET0031 — 禁止 new Proto / Message 类
`MessageObject`Proto 生成)走对象池,必须用工厂:
```csharp
// ❌
HeroInfo hero = new() { heroId = 1 };
Hero_HeroInfo notice = new() { hero = info };
// ✅
HeroInfo hero = HeroInfo.Create();
hero.heroId = 1;
Hero_HeroInfo notice = Hero_HeroInfo.Create();
notice.hero = info;
```
---
## ET0032 — Model/ModelView 禁止非 Entity 类
Model 程序集理论上只放 Entity / Component / Proto / `struct`。普通工具类/DTO 要么挪走,要么加 `[EnableClass]`
```csharp
// ❌ 在 Scripts/Model/Share/ 下
namespace ET.Server
{
public sealed class MongoDBComponent : IDBComponent { ... } // ET0032
}
// ✅
namespace ET.Server
{
[EnableClass]
public sealed class MongoDBComponent : IDBComponent { ... }
}
```
实战上经常用 Model 层放 `static` 工具:因为 Hotfix 不允许静态字段,需要持有锁/字典之类的静态状态时**只能**放在 Model + `[EnableClass]`
---
## ET0013 — 静态类间环依赖
```csharp
// ❌
public static class BagComponentSystem
{
public static void AddItem(this BagComponent self, ...) {
BagNoticeHelper.NotifyItemChange(...);
}
}
public static class BagNoticeHelper
{
public static void NotifyItemList(BagComponent bag) {
bag.GetAllItems(); // 调到 BagComponentSystem形成环
}
}
// ✅ 让 BagNoticeHelper 内联自己的小逻辑,不再调上层
public static class BagNoticeHelper
{
public static void NotifyItemList(BagComponent bag) {
foreach (var unitRef in bag.ItemMap.Values) {
ItemUnit unit = unitRef;
list.items.Add(BagMapper.ToProto(unit));
}
}
}
```
排查:报错信息会列出所有 `A -> B``B -> A` 的调用点。
---
## ET0015 — static 字段必须 `[StaticField]`
```csharp
// ❌
namespace ET
{
public class Foo
{
private static int counter; // ET0015
}
}
// ✅
namespace ET
{
public class Foo
{
[StaticField]
private static int counter;
}
}
```
在 Hotfix 程序集里 ET0015 + ET0004 会同时触发,唯一出路是**挪到 Model**。
---
## ET0024 / ET0025 — EntitySystem 必须在 partial 类里
```csharp
// ❌
public static class HeroSystem
{
private static void Awake(this Hero self) { ... } // ET0024
}
// ✅
[EntitySystemOf(typeof(Hero))]
[FriendOf(typeof(Hero))]
public static partial class HeroSystem
{
[EntitySystem]
private static void Awake(this Hero self, int configId)
{
self.ConfigId = configId;
}
}
```
ET 用源码生成器在 partial 的另一半生成 `HeroAwakeSystem` 类。**忘记 `partial`** 是常见错误。
---
## 其他规则(出错概率低,简要列出)
| ID | 含义 |
|---|---|
| ET0001 | `AddChild<T>` 的 T 必须在 `[ChildOf]` 声明里 |
| ET0003 | Entity 子类不能写构造函数 |
| ET0005 | Hotfix 类必须 static |
| ET0006 | Entity 类不能写实例方法(要写成扩展方法在 System 里) |
| ET0007 | Component 必须有 `[ComponentOf]` 声明 |
| ET0008 | 同步方法里不能调 `await ETTask` |
| ET0009 | async 方法里不能丢弃 ETTask |
| ET0010 | 不允许 delegate 字段 |
| ET0011 | UniqueId 范围检查 |
| ET0012 | UniqueId 重复 |
| ET0014 | Entity 内不能用 child component |
| ET0016~0019 | ETCancellationToken 链路检查 |
| ET0020 | Entity 字段声明位置 |
| ET0021 | async 方法返回类型必须 ETTask |
| ET0022 | Client 类不能在 Server 程序集 |
| ET0023 | LSEntity float 字段检查(确定性帧同步) |
| ET0026 | FiberLog 使用规则 |
| ET0027 | EntityHashCode 检查 |
| ET0028 | EntityComponentChild 检查 |
| ET0029 | Entity 不能声明泛型类型 |
| ET0030 | NetMessage 必须从 Proto 生成 |
| ET1001 | ETSystem 方法必须在 static partial 类 |
具体规则触发时去看对应分析器源码:
```
cn.etetet.sourcegenerator/DotNet~/ET.SourceGenerator/Analyzer/<RuleName>.cs
cn.etetet.sourcegenerator/DotNet~/ET.SourceGenerator/Config/DiagnosticIds.cs
```