172 lines
7.4 KiB
Markdown
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.

# ET 程序集分层与 asmref 完整规则
## 6 个核心程序集
| 程序集 | 由谁定义 | 装哪些代码 |
|---|---|---|
| `ET.Core` | `cn.etetet.core/Runtime/Core/ET.Core.asmdef` | 框架基础,不可修改 |
| `ET.Model` | `cn.etetet.statesync/Runtime/Model/ET.Model.asmdef` | Entity/Component 数据定义、Proto 消息类、占位/工具类(加 `[EnableClass]` |
| `ET.ModelView` | `cn.etetet.statesync/Runtime/ModelView/ET.ModelView.asmdef` | YIUI 视图组件、UIBindCDETable 派生类 |
| `ET.Hotfix` | `cn.etetet.statesync/Runtime/Hotfix/ET.Hotfix.asmdef` | 业务 System / Service / Helper / Handler |
| `ET.HotfixView` | `cn.etetet.statesync/Runtime/HotfixView/ET.HotfixView.asmdef` | YIUI 事件、GM 命令、客户端 RPC handler |
| `ET.Loader` | `cn.etetet.loader/...` | 启动器 |
> ET.Model.asmdef 的 `defineConstraints` 是 `["INITED", "IS_COMPILING || UNITY_EDITOR"]` — 项目必须先被 ET 框架"初始化"过(写入 `INITED` symbol所有 asmref 才会激活。新克隆的工程要先走一次 ET 初始化流程。
---
## asmref让你的包加入框架程序集
每个 `cn.etetet.<pkg>` 包**不能**自己定义 asmdef必须用 asmref 把代码"塞"进上面 6 个程序集。
### 标准目录布局
```
cn.etetet.mypkg/
├── package.json # 声明依赖
├── Ignore.ET.MyPkg.asmdef # 占位IGNORE constraint
├── Ignore.ET.MyPkg.asmdef.meta
├── Proto/ # 只放 .proto
│ └── MyPkgOuter_C_4000.proto
└── Scripts/
├── Model/
│ ├── Share/AssemblyReference.asmref # → ET.Model
│ ├── Client/AssemblyReference.asmref # → ET.Model
│ └── Server/AssemblyReference.asmref # → ET.Model
├── ModelView/
│ └── Client/AssemblyReference.asmref # → ET.ModelView
├── Hotfix/
│ ├── Share/AssemblyReference.asmref # → ET.Hotfix
│ ├── Client/AssemblyReference.asmref # → ET.Hotfix
│ └── Server/AssemblyReference.asmref # → ET.Hotfix
└── HotfixView/
└── Client/AssemblyReference.asmref # → ET.HotfixView
```
### AssemblyReference.asmref 内容(固定)
```json
{ "reference": "ET.Model" }
```
```json
{ "reference": "ET.ModelView" }
```
```json
{ "reference": "ET.Hotfix" }
```
```json
{ "reference": "ET.HotfixView" }
```
### Ignore.<Name>.asmdef 内容(固定)
```json
{
"name": "Ignore.ET.MyPkg",
"rootNamespace": "",
"references": [],
"defineConstraints": ["IGNORE"],
"autoReferenced": true
}
```
`defineConstraints: ["IGNORE"]` 让这个 asmdef 永远不参与编译 — 它的存在只是为了占位(避免 Unity 找不到 .meta真正生效的是各子目录里的 asmref。
---
## 哪个代码放哪一层(决策表)
| 你想写的代码 | 放哪 | 关键约束 |
|---|---|---|
| `class Hero : Entity, IAwake<int>` | `Scripts/Model/Server/Hero.cs` | 只能字段,不能写方法。需要 `[ChildOf(typeof(HeroComponent))]` |
| `[ComponentOf(typeof(Player))] class HeroComponent : Entity, IAwake` | `Scripts/Model/Server/HeroComponent.cs` | 同上 |
| 客户端缓存 `class HeroComponent : Entity, IAwake { Dictionary<long, HeroInfo> }` | `Scripts/Model/Client/HeroModels.cs` | 同名服务端类客户端可独立定义 |
| `[EntitySystemOf(typeof(Hero))] partial class HeroSystem { Awake/Update }` | `Scripts/Hotfix/Server/HeroSystem.cs` | partial函数标 `[EntitySystem]` |
| `static class HeroService { TrySkillUp(player, hero) }` | `Scripts/Hotfix/Server/HeroService.cs` | 加 `[FriendOf(typeof(Hero))]` |
| `RpcMessageHandler<C2G_X, R2C_X>` 子类 | `Scripts/Hotfix/Server/C2G_XHandler.cs` | **不能**有非 const 字段/属性 |
| `MessageHandler<Scene, X>` 客户端 | `Scripts/Hotfix/Client/X_Handler.cs` | 同上 |
| 锁对象 / 字典 / 静态状态工具类 | `Scripts/Model/Share/` + `[EnableClass]` | 因为 Hotfix 不允许静态字段 |
| Proto 生成的 Message 类 | 不要自己写,跑 Proto2CS | 输出到 `cn.etetet.proto/CodeMode/` |
| YIUI 视图组件 `class XXXViewComponent : Entity` | `Scripts/ModelView/Client/XXX.cs` | |
| `[GM(EGMType.Common, ...)]` 命令 | `Scripts/HotfixView/Client/GM/X.cs` | 必须在 HotfixView 才被 GMAttribute 扫到 |
| `AEvent<Scene, YIUIEventInitializeAfter>` handler | `Scripts/HotfixView/Client/` | |
---
## 新建一个业务包:完整步骤
```
Task Progress:
- [ ] 1. 复制 cn.etetet.statesync 整个目录为 cn.etetet.<newpkg>
- [ ] 2. 删除 Runtime/ 下的 ET.*.asmdef 文件(这些是核心程序集,不能在新包里)
- [ ] 3. 改 package.json 的 name / displayName / dependencies
- [ ] 4. 修改 Ignore.ET.Statesync.asmdef → Ignore.ET.<NewPkg>.asmdefname 字段同步改
- [ ] 5. 确保 Scripts/**/AssemblyReference.asmref 都还在content 不需改)
- [ ] 6. 如果不需要 ModelView / HotfixView删对应目录的 asmref避免无意义编译
- [ ] 7. Unity Assets/Refresh确认 Console 无报错
- [ ] 8. 写 Proto → 跑 Proto2CS → 写 Model → 写 Hotfix
```
### package.json 依赖最小集
```json
{
"name": "cn.etetet.mypkg",
"displayName": "ET.MyPkg",
"version": "1.0.0",
"dependencies": {
"cn.etetet.core": "1.0.0",
"cn.etetet.login": "1.0.0",
"cn.etetet.logging": "1.0.0",
"cn.etetet.console": "1.0.0"
}
}
```
按需补:`cn.etetet.bag` / `cn.etetet.hero` / `cn.etetet.yiuigm` 等。
---
## 临时屏蔽 / 启用整个包
**屏蔽**:删除 `Scripts/**/AssemblyReference.asmref` 及对应 `.meta`,保留 `Ignore.*.asmdef`。包代码全部不参与编译。
**启用**:把 asmref 加回来内容如上节模板。Unity 会自动识别。
本次会话用这招屏蔽了 `cn.etetet.gacha`
```
删除cn.etetet.gacha/Scripts/Hotfix/{Client,Server}/AssemblyReference.asmref
删除cn.etetet.gacha/Scripts/Model/{Client,Server}/AssemblyReference.asmref
保留cn.etetet.gacha/Ignore.ET.Gacha.asmdef
```
---
## 常见踩坑
1. **代码静默失踪**:新加的 cs 文件**所在目录上行**没有 asmref → 文件不参与任何程序集 → 调用方报"找不到类型"。检查方法:
```
Glob: cn.etetet.<pkg>/**/*.asmref
```
每个有 cs 文件的子目录必须有 asmref 上溯。
2. **方向错误**:把 Helper 写到 `Scripts/Model/Server/` → ET0032。把 Entity 写到 `Scripts/Hotfix/Server/` → 各种诡异错误Hotfix 不允许字段)。决策表见上。
3. **客户端代码引用了 UnityEngine**`Scripts/Hotfix/Client/` 是 `ET.Hotfix` 程序集,**不能** `using UnityEngine`。需要 UnityEngine API 的代码必须放 `Scripts/HotfixView/Client/` 或 `Scripts/ModelView/Client/`。
4. **Model 程序集报 `Define` / `GlobalConfig` / `Resources` 未找到**:同样 UnityEngine 引用问题。Model 层禁止依赖 UnityEngine。需要的话挪去 ModelView 或者用反射延后调用。
---
## 跨包引用的最佳实践
- 在 `package.json.dependencies` 显式声明依赖。
- **避免环依赖**`login` 不要依赖 `bag/hero` 这种业务包;让业务包依赖 `login` 暴露的接口。如果非要双向,用 Invoke 契约(看 `cn.etetet.<pkg>invoke` 包模式)。
- 不允许 `Hotfix/Client` 调用 `Hotfix/Server` 代码(编译会过但语义错)。共享逻辑放 `Hotfix/Share`。