跳到正文
Virok
已成形

Unity asmdef 与编辑器脚本:Player 构建失败的经典原因

2 分钟

AI 摘要

Unity 项目中若某目录缺少 asmdef,其脚本会落入 Assembly CSharp,导致带 UnityEditor 引用的编辑器脚本被打包进 Player。解决方案包括:为 Editor 子目录添加含 includePlatforms: Editor 的 asmdef、用 if UNITY_EDITOR 包裹、或将脚本放入 Editor/ 目录(Unity 内建规则)。推荐三层防护同时生效,兼顾安全性与编译性能。

WOTW3D 里踩过一次:ScriptsGameCore/Level/ 目录下没有 asmdef 文件,于是它归属默认的 Assembly-CSharp。而 Assembly-CSharp 里的脚本在 Player 构建时是会被编译进去的——包括那些 using UnityEditor; 的编辑器脚本。

结果就是开发时一切正常,一打包就报:

error CS0234: The type or namespace name 'UnityEditor' does not exist
in the namespace 'Unity' (are you missing an assembly reference?)

根因

Unity 的编译单元是程序集。没有 asmdef 的脚本全部落进 Assembly-CSharp,而这个程序集在两个“编译平台”下都会被编译:

  • Editor 平台:能访问 UnityEditor
  • Player 平台:不能

编辑器脚本没被隔离,就会被 Player 编译流程抓到。

三种解法

1. 加 asmdef,限定只编译给 Editor。

ScriptsGameCore/Level/Editor/ 下放一个 WOTW.Level.Editor.asmdef

{
  "name": "WOTW.Level.Editor",
  "references": ["WOTW.Level"],
  "includePlatforms": ["Editor"],
  "excludePlatforms": [],
  "allowUnsafeCode": false,
  "overrideReferences": false,
  "precompiledReferences": [],
  "autoReferenced": true,
  "defineConstraints": [],
  "versionDefines": [],
  "noEngineReferences": false
}

includePlatforms: ["Editor"] 是核心——这个程序集只在编辑器下编译。

2. 用 #if UNITY_EDITOR 包住。

#if UNITY_EDITOR
using UnityEditor;

[CustomEditor(typeof(LevelDef))]
public sealed class LevelDefEditor : Editor { /* ... */ }
#endif

3. 文件名带 .Editor.cs 后缀或者放进 Editor/ 目录。

Unity 对名为 Editor 的文件夹有内建规则:里面的脚本自动只在编辑器下编译。这是最简单的做法,但只对顶层路径中含 Editor 目录的脚本生效。

我的选择

两者都做:目录隔离 + asmdef 显式声明 + #if UNITY_EDITOR 兜底

听起来冗余,但这三层的失效模式不同:

  • Editor/ 目录规则:有人把脚本移到别处就失效
  • asmdef:有人新建文件忘了更新引用就失效
  • #if UNITY_EDITOR:有人复制粘贴时漏了就失效

只用一层的话,总有一天会在赶进度的晚上破掉。三层全上的成本是每条编辑器脚本多两行,我愿意付。

顺带:asmdef 的编译速度收益

加 asmdef 还有个副作用是好的——改代码时的重编译变快了

Unity 的编译单元是程序集,改一个文件会重编整个程序集。没有 asmdef 时所有脚本挤在 Assembly-CSharp 里,改一行代码要重编全部。拆成 WOTW.Sim / WOTW.Presentation / WOTW.Level 之后,改 Sim 层只重编 Sim 那个程序集。

而且 WOTW.Sim 不依赖 UnityEngine(这是架构硬约束,见确定性模拟那篇),所以它是纯 C# —— 可以单独拿出来给测试工程引用,也可以设成 noEngineReferences: true

这是一条笔记,不是成稿文章。它可能不完整、可能有错,也可能过段时间就被我推翻。 想看成体系的文章,去 Blog