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/EditorGame 模块内 Editor 辅助代码
Assets/Tests/EditorEditorMode 测试

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导入资源时自动执行模型、纹理、音频统一设置
InitializeOnLoadUnity 编译/打开后注册菜单状态、Editor 回调、后台服务
Build Processor/PipelineBuild 前后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当前地图随机组和结构检查
MapDataCheckToolsAssets/Map/MapDataCheckAll,批量数据检查
MapGatherEditorToolsStarlit/MapGather,收集地图 Prefab 引用
PortalSetterGameObject/地图/检查Portal,统一 Link area/方向
NavMeshPrefabInstance Inspector对单个导航 Prefab Bake/Clear

项目使用地图局部导航 Prefab 和局部 Lightmap 场景,不应把 Unity 全局 Bake 当作最终流水线。具体操作见:

地图编辑器与地图层级

导航 Prefab 检查

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 -> 生成代码/数据 -> 复制进工程
}

完整阶段:

  1. 从命令行参数或 EditorPrefs 取得 ConfigRootDir。
  2. 扫描 Excel,过滤 Office 临时文件。
  3. 收集本地化文本。
  4. CfgStructDataParser 解析字段名、注释、类型、KEY1/KEY2 和数据行。
  5. 生成配置类、LocalizeId 和数据。
  6. 从 GenDatabase 复制代码到 Assets/Code/Core/Database/Class。
  7. 复制数据到 Assets/Resources_moved/Database。
  8. SaveAssets、Refresh 并删除中间目录。

重要风险:

  • GenerateAll2Game 会删除并重建中间 GenDatabase。
  • 生成类和运行时数据必须同批提交。
  • 前后端如果各自生成,必须确认表版本和字段语义一致。
  • 不能在生成物里做永久手工修复,下次生成会覆盖。

6. Jenny 与其他代码生成

工具产物
Jenny-Server.batEntitas Entity、Matcher、Lookup
ViewSettingGeneratorServices.View.ViewSettings.cs
GuidObjectTypeGeneratorGUID/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(...)

导入器规则必须满足:

  1. 同一资源重复 Reimport 结果一致。
  2. 只处理明确路径/标签,避免扫描所有第三方资产。
  3. 改设置前比较旧值,减少 Import 循环。
  4. 平台压缩、Read/Write、Mesh、音频质量有明确依据。
  5. 批量规则修改先在小目录验证,再全量 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 诊断
GMToolsEditor 内 GM/运行辅助
QuickStartGame打开启动场景并 Play
SearchReference查找资源引用
RemoveMissingScriptsFromProject清理 Missing Script,操作前应限定范围
UIEditorToolsUI Raycast、PlayerPrefs 等检查
ValidationsGameObject/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

  1. 先确认 Unity Console 没有编译错误。
  2. 检查脚本属于哪个 asmdef,以及 includePlatforms 是否为 Editor。
  3. 菜单不出现时检查 MenuItem 静态方法签名、条件编译和重复菜单。
  4. CustomEditor 不生效时检查目标类型、CanEditMultipleObjects 和 Inspector 错误。
  5. 生成内容过期时确认源数据、DLL 和生成器版本。
  6. 导入死循环时看 AssetPostprocessor 是否每次都无条件写设置。
  7. 构建差异时记录 BuildTarget、Define Symbols、配置根、资源索引和 Git revision。
  8. 批量操作后立即查看版本控制,确认没有无关 meta、场景或 Prefab 变化。

14. 工具分类速查

我想做什么先看哪里
摆地图、刷怪点、TriggerAssets/Maps/Scripts/Editor
导出地图MapGatherEditorTools、13
Bake 导航NavMeshPrefabInstance、20
Bake Lightmap光照工具和 19
生成配置ConfigOption、16
生成 ECSJenny.properties、Jenny-Server.bat
生成 View 映射ViewSettingGenerator
统一资源导入EditorResourceSetting
打 Bundle/补丁AssetsBundleTools
打 APK/iOSEditorCommand
查同步问题StateSyncDebugTools、22

15. 关联阅读


上一篇:客户端 Rendering