Unity Editor 扩展:地图、配置、资源与构建工具 private
Unity Editor 扩展:地图、配置、资源与构建工具
本篇只讲制作期和构建期工具。运行时 Logic 见 23,运行时 Rendering 见 24。Editor 扩展的输出会进入运行时,但 Editor API 本身不能进入 Player。
1. Editor 扩展的边界
Editor 扩展负责把人可编辑的源内容变成运行时可消费的资产、代码和数据:
flowchart LR
Source[场景 / Excel / 模型 / 纹理 / Prefab] --> Editor[Editor 扩展]
Editor --> Validate[检查与预览]
Editor --> Generate[生成代码/配置/地图数据]
Editor --> Import[统一导入设置]
Editor --> Build[AssetBundle / Player / Patch]
Generate --> Runtime[客户端运行时]
Generate --> Server[服务端数据]
Build --> Package[发布包]
它不应该:
- 在 Player 中执行 UnityEditor API。
- 成为战斗规则或运行时状态的唯一来源。
- 静默修改大量资产而不提供预览、日志或撤销路径。
- 把本机绝对路径、密钥和环境地址提交进共享配置。
2. 代码在哪里
| 目录 | 责任 |
|---|---|
| Assets/Editor | 通用 Editor 菜单、导入、资源、配置、构建、诊断 |
| Assets/Maps/Scripts/Editor | 地图作者组件、Spawner/Trigger/随机组和 Inspector |
| Assets/Code/Game/OLogic/Editor | 与具体运行时组件紧邻的 Inspector/检查工具 |
| Assets/Code/Game/Editor | Game 模块内 Editor 辅助代码 |
| Assets/Tests/Editor | EditorMode 测试 |
Assets/Editor/CommonEditor.asmdef 的 includePlatforms 只有 Editor,并引用 GameAssemblyNew、CoreAssembly、Addressables.Editor 等。这是明确的编译隔离。
但工程仍有两个需要警惕的现实:
- GameAssemblyNew.asmdef 引用了 libx.Editor,主运行时程序集边界并不完全纯净。
- OLogic 下存在名为 Editor 的代码,必须检查程序集归属和 UNITY_EDITOR 条件,而不能只依赖目录视觉效果。
新增工具优先进入专用 Editor asmdef,运行时代码不反向依赖 Editor 程序集。
3. 五种扩展入口
| 入口 | 触发方式 | 适合用途 |
|---|---|---|
| MenuItem | 手动点击菜单 | 导出、检查、批处理、构建 |
| CustomEditor | 选中组件时 | 专用 Inspector、Bake/Clear、参数校验 |
| AssetPostprocessor | 导入资源时自动执行 | 模型、纹理、音频统一设置 |
| InitializeOnLoad | Unity 编译/打开后注册 | 菜单状态、Editor 回调、后台服务 |
| Build Processor/Pipeline | Build 前后 | Shader 裁剪、平台工程修改、产物收集 |
选择原则:可能产生大量改动的操作应由显式 MenuItem 发起;导入规则可以自动化,但要幂等且不能每次 Reimport 反复改写。
4. 地图制作扩展
地图相关工具分两类:
4.1 作者组件和 Inspector
Assets/Maps/Scripts/Editor 包含:
- MapRoot、ObjectSpawnPoint。
- MonsterWaveGroup、MonsterRandomGroup、HeroSpawnRandomGroup。
- RangeTrigger、GroupTrigger、Portal、SafeZone。
- 各种 OverrideExtension 和 CustomEditor。
这些组件让策划在场景中摆放结构化数据,不等于最终运行时对象。地图导出时会 Gather 成 MapElement 和二进制数据。
4.2 检查和导出菜单
| 工具 | 入口/作用 |
|---|---|
| MapEditorChecker | 当前地图随机组和结构检查 |
| MapDataCheckTools | Assets/Map/MapDataCheckAll,批量数据检查 |
| MapGatherEditorTools | Starlit/MapGather,收集地图 Prefab 引用 |
| PortalSetter | GameObject/地图/检查Portal,统一 Link area/方向 |
| NavMeshPrefabInstance Inspector | 对单个导航 Prefab Bake/Clear |
项目使用地图局部导航 Prefab 和局部 Lightmap 场景,不应把 Unity 全局 Bake 当作最终流水线。具体操作见:


5. 配置生成扩展
核心入口是 Assets/Editor/Config/ConfigOption.cs:
[MenuItem("Starlit/ConfigOption/GenerateAll2Game")]
static public void GenerateAll2Game()
{
var configRoot = GetConfigPath();
var files = Directory
.GetFiles(configRoot, "*.xlsx", SearchOption.TopDirectoryOnly)
.Where(v => !Path.GetFileName(v).StartsWith("~"))
.ToList();
// 读取本地化 -> 解析 Excel -> 生成代码/数据 -> 复制进工程
}
完整阶段:
- 从命令行参数或 EditorPrefs 取得 ConfigRootDir。
- 扫描 Excel,过滤 Office 临时文件。
- 收集本地化文本。
- CfgStructDataParser 解析字段名、注释、类型、KEY1/KEY2 和数据行。
- 生成配置类、LocalizeId 和数据。
- 从 GenDatabase 复制代码到 Assets/Code/Core/Database/Class。
- 复制数据到 Assets/Resources_moved/Database。
- SaveAssets、Refresh 并删除中间目录。
重要风险:
- GenerateAll2Game 会删除并重建中间 GenDatabase。
- 生成类和运行时数据必须同批提交。
- 前后端如果各自生成,必须确认表版本和字段语义一致。
- 不能在生成物里做永久手工修复,下次生成会覆盖。
6. Jenny 与其他代码生成
| 工具 | 产物 |
|---|---|
| Jenny-Server.bat | Entitas Entity、Matcher、Lookup |
| ViewSettingGenerator | Services.View.ViewSettings.cs |
| GuidObjectTypeGenerator | GUID/ObjectType 映射代码 |
| ConfigOption | 配置类、LocalizeId 和运行时数据 |
| Protobuf 工具 | 客户端/服务端协议类 |
Jenny 读取 Library/ScriptAssemblies/GameAssemblyNew.dll。Unity 必须先成功编译,生成器才能看到最新 Component。Jenny 不是 Login/Lobby/Battle 服务器。
生成物识别规则:
- 文件头标注 generated/do not modify。
- 位于 OGame/Generated 或配置生成目录。
- 可以由菜单或脚本稳定重建。
改生成物前先找到源定义和生成入口。
7. 资源导入扩展
Assets/Editor/AssetsImporter/EditorResourceSetting.cs 继承 AssetPostprocessor,覆盖模型、纹理、Sprite、音频和用户属性处理。
典型入口:
OnPostprocessModel(GameObject)
OnPostprocessTexture(Texture2D)
OnPostprocessSprites(Texture2D, Sprite[])
OnPostprocessAudio(AudioClip)
OnPostprocessGameObjectWithUserProperties(...)
导入器规则必须满足:
- 同一资源重复 Reimport 结果一致。
- 只处理明确路径/标签,避免扫描所有第三方资产。
- 改设置前比较旧值,减少 Import 循环。
- 平台压缩、Read/Write、Mesh、音频质量有明确依据。
- 批量规则修改先在小目录验证,再全量 Reimport。
相关诊断工具还有 TextureEditorTools、ModelEditorTools、OptimizePngTool 和 SearchMaterialForModel。
8. AssetBundle 和资源索引工具
Assets/Editor/AssetsBundleTools 包含:
- BuildAB:选择资源或全量构建 Bundle。
- AssetsBundleGen:补丁包、差异包、依赖和 Lightmap 引用。
- AssetsBundleUtils:同名文件、依赖和包差异检查。
- AssetsTools:选中资源构建、Shader/Font 依赖分析。
构建前确认:
- 当前 BuildTarget 正确。
- Addressables/AssetBundle 标签和资源路径索引已更新。
- 地图 bytes、Lightmap、导航 Prefab 和 AssetsMapPath 来自同一批。
- 输出目录不是被其他构建占用。
- Patch/Basis 配置对应正确版本,避免误删工程资产。
9. 构建与 CI 扩展
Assets/Editor/Command/EditorCommand.cs 提供 iOS、APK 和测试构建入口,最终调用 BuildPipeline.BuildPlayer。EditorCommandBuildPatch 处理补丁和地区/SDK切换。
Assets/Editor/XCodeConfig/XCodeConfig.cs 在 iOS 构建后修改 Xcode 工程。ShaderStripConfig 通过 IPreprocessShaders 控制 Shader Variant。
构建脚本应把参数来源分成:
- 代码库默认值。
- 本地 EditorPrefs。
- CI 命令行参数。
- 不入库的密钥/签名环境。
不要用提交本地配置的方式修复 CI,也不要在文档里记录密码和签名密钥。
10. 调试和检查扩展
| 工具 | 用途 |
|---|---|
| StateSyncDebugTools | 查看状态同步和 PacketCache 诊断 |
| GMTools | Editor 内 GM/运行辅助 |
| QuickStartGame | 打开启动场景并 Play |
| SearchReference | 查找资源引用 |
| RemoveMissingScriptsFromProject | 清理 Missing Script,操作前应限定范围 |
| UIEditorTools | UI Raycast、PlayerPrefs 等检查 |
| Validations | GameObject/UI 有效性验证 |
诊断工具应该只读或显式确认修改范围。批量清理 Missing Script、替换 Prefab、本地化替换等会改大量资产,执行前先看版本控制变化。
11. 为什么 Editor 和 Runtime 必须隔离
如果运行时代码依赖 UnityEditor:
- Player 构建会失败或产生平台差异。
- 单元测试无法在 Player/服务器环境复用。
- 业务逻辑只能在 Unity 编辑器中运行。
- 批处理和 CI 的程序集依赖更脆弱。
推荐依赖方向:
flowchart LR
Runtime[Runtime Assembly] --> Contract[数据结构/接口]
Editor[Editor Assembly] --> Runtime
Editor --> Contract
Editor --> UnityEditorAPI[UnityEditor API]
Runtime -.禁止.-> Editor
Editor 可以引用 Runtime,用相同数据结构生成资产;Runtime 不能反向引用 Editor。
12. 新增 Editor 工具的模板
12.1 手动批处理
public static class ExampleTools
{
[MenuItem("Starlit/Example/Validate Selection")]
private static void ValidateSelection()
{
foreach (var obj in Selection.objects)
{
// 只检查,汇总问题;需要修改时使用 Undo.RecordObject
}
}
}
12.2 实现要求
- 放入 Editor-only asmdef。
- 菜单名按 Game、Starlit、Assets、GameObject 的既有语义。
- 修改场景/Prefab 前调用 Undo.RecordObject 或对应 Prefab API。
- 长任务显示可取消 ProgressBar,并在 finally 中 ClearProgressBar。
- 文件路径使用 Application.dataPath/AssetDatabase,避免提交本机绝对路径。
- 生成过程可重复执行,输出顺序稳定。
- 错误日志带资源路径、对象名和处理阶段。
- 批处理结束 SaveAssets/Refresh,但不要在每个对象上调用。
- 为解析和纯数据部分写 EditorMode 测试。
13. Editor 工具排错 SOP
- 先确认 Unity Console 没有编译错误。
- 检查脚本属于哪个 asmdef,以及 includePlatforms 是否为 Editor。
- 菜单不出现时检查 MenuItem 静态方法签名、条件编译和重复菜单。
- CustomEditor 不生效时检查目标类型、CanEditMultipleObjects 和 Inspector 错误。
- 生成内容过期时确认源数据、DLL 和生成器版本。
- 导入死循环时看 AssetPostprocessor 是否每次都无条件写设置。
- 构建差异时记录 BuildTarget、Define Symbols、配置根、资源索引和 Git revision。
- 批量操作后立即查看版本控制,确认没有无关 meta、场景或 Prefab 变化。
14. 工具分类速查
| 我想做什么 | 先看哪里 |
|---|---|
| 摆地图、刷怪点、Trigger | Assets/Maps/Scripts/Editor |
| 导出地图 | MapGatherEditorTools、13 |
| Bake 导航 | NavMeshPrefabInstance、20 |
| Bake Lightmap | 光照工具和 19 |
| 生成配置 | ConfigOption、16 |
| 生成 ECS | Jenny.properties、Jenny-Server.bat |
| 生成 View 映射 | ViewSettingGenerator |
| 统一资源导入 | EditorResourceSetting |
| 打 Bundle/补丁 | AssetsBundleTools |
| 打 APK/iOS | EditorCommand |
| 查同步问题 | StateSyncDebugTools、22 |