7.4 KiB
Raw Permalink Blame History

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 内容(固定)

{ "reference": "ET.Model" }
{ "reference": "ET.ModelView" }
{ "reference": "ET.Hotfix" }
{ "reference": "ET.HotfixView" }

Ignore..asmdef 内容(固定)

{
    "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 依赖最小集

{
  "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. 客户端代码引用了 UnityEngineScripts/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