172 lines
7.4 KiB
Markdown
172 lines
7.4 KiB
Markdown
# 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>.asmdef,name 字段同步改
|
||
- [ ] 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`。
|