【Unity AssetModificationProcessor介绍】

发布于:2025-07-31 ⋅ 阅读:(20) ⋅ 点赞:(0)

Unity AssetModificationProcessor 全面解析

AssetModificationProcessor 是 Unity 编辑器扩展的核心接口之一,它允许开发者在资源生命周期关键节点插入自定义逻辑。这个强大的工具可以实现自动化资源管理、规范团队工作流程、提升开发效率。

核心功能与作用

AssetModificationProcessor 提供了一系列回调方法,在以下资源操作时触发:

资源创建
OnWillCreateAsset
资源保存
OnWillSaveAssets
资源移动/重命名
OnWillMoveAsset
资源删除
OnWillDeleteAsset

关键方法详解

1. OnWillCreateAsset(string path)

  • 触发时机:资源即将创建时(如新建脚本、材质等)
  • 参数path - 新资源的路径(包含 .meta 后缀)
  • 应用场景
    • 自动添加脚本头部注释
    • 设置新资源的默认属性
    • 初始化资源元数据

2. OnWillSaveAssets(string[] paths)

  • 触发时机:资源即将保存到磁盘前
  • 参数paths - 即将保存的资源路径数组
  • 返回值:可修改后返回的路径数组
  • 应用场景
    • 自动优化资源(压缩纹理、简化网格)
    • 执行代码规范检查
    • 添加版本控制信息

3. AssetMoveResult OnWillMoveAsset(string sourcePath, string destinationPath)

  • 触发时机:资源即将移动或重命名前
  • 参数
    • sourcePath - 原始路径
    • destinationPath - 目标路径
  • 返回值AssetMoveResult 枚举,可控制操作结果
  • 应用场景
    • 强制资源命名规范
    • 更新依赖引用
    • 记录资源迁移历史

4. AssetDeleteResult OnWillDeleteAsset(string assetPath, RemoveAssetOptions options)

  • 触发时机:资源即将删除前
  • 参数
    • assetPath - 待删除资源路径
    • options - 删除选项(如是否移到回收站)
  • 返回值AssetDeleteResult 枚举,可阻止删除
  • 应用场景
    • 防止误删关键资源
    • 删除前备份
    • 清理关联资源

实际应用案例(脚本放在Editor文件夹下)

1. `OnWillCreateAsset回调用于自动脚本头部注释

using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine;

public class ScriptsHeader : AssetModificationProcessor
{
    private const string author = "XXX";
    private const string email = "xxxx@qq.com";
    private const string firstVersion = "1.0.0";

    public static void OnWillCreateAsset(string path)
    {
        // 仅处理C#脚本
        if (!path.EndsWith(".cs"))
            return;

        // 延迟处理确保文件已创建
        EditorApplication.delayCall += () => ProcessScriptFile(path);
    }

    private static void ProcessScriptFile(string metaPath)
    {
        try
        {
            // 获取脚本完整路径
            string scriptPath = GetScriptPath(metaPath);

            // 确保文件存在
            if (!File.Exists(scriptPath))
            {
                Debug.LogWarning($"[ScriptHeader] 文件不存在: {scriptPath}");
                return;
            }

            // 读取文件内容
            string content = File.ReadAllText(scriptPath, Encoding.UTF8);

            // 检查是否已添加头部(避免重复添加)
            if (content.Contains("/* ======================================================="))
                return;

            // 构建头部注释
            string header = BuildHeaderTemplate();

            // 在文件开头插入注释
            File.WriteAllText(scriptPath, header + content, Encoding.UTF8);

            // 刷新Unity数据库
            AssetDatabase.Refresh();

            Debug.Log($"[ScriptHeader] 已为 {Path.GetFileName(scriptPath)} 添加头部注释");
        }
        catch (System.Exception ex)
        {
            Debug.LogError($"[ScriptHeader] 添加失败: {ex.Message}");
        }
    }

    private static string GetScriptPath(string metaPath)
    {
        // 移除.meta后缀
        string relativePath = metaPath.Replace(".meta", "");

        // 获取项目根目录
        string projectRoot = Directory.GetParent(Application.dataPath).FullName;

        // 组合完整路径
        return Path.Combine(projectRoot, relativePath);
    }

    private static string BuildHeaderTemplate()
    {
        return string.Format(
            "/* =======================================================\r\n"
          + " *  Unity版本:{0}\r\n"
          + " *  作    者:{1}\r\n"
          + " *  邮    箱:{2}\r\n"
          + " *  创建时间:{3}\r\n"
          + " *  当前版本:{4}\r\n"
          + " *  主要功能:\r\n"
          + " *  详细描述:\r\n"
          + " *  修改记录:\r\n"
          + " * =======================================================*/\r\n\r\n",
            Application.unityVersion,
            author,
            email,
            System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
            firstVersion);
    }
}

2. OnWillMoveAsset用于在移动包含脚本文件的文件夹时提供确认提示的例子

/* =======================================================
 *  Unity版本:2022.3.60f1c1
 *  作    者:XXX
 *  邮    箱:xxxx@qq.com
 *  创建时间:2025-07-29 15:30:14
 *  当前版本:1.0.0
 *  主要功能:
 *  详细描述:
 *  修改记录:
 * =======================================================*/

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

public class OnWillMoveAssetPrompt : UnityEditor.AssetModificationProcessor
{
    /// <summary>
    /// 即将移动资产时调用
    /// </summary>
    /// <param name="sourcePath">资产当前路径</param>
    /// <param name="destinationPath">资产要移动到的路径</param>
    /// <returns></returns>
    public static AssetMoveResult OnWillMoveAsset(
        string sourcePath, string destinationPath)
    {
        //Debug.Log(string.Format("SourcePath:{0}  " +
        //    "DestinationPath:{1}", sourcePath, destinationPath));
        if (AssetDatabase.IsValidFolder(sourcePath))
        {
            //在sourcePath文件夹中查找是否包含脚本文件
            if (AssetDatabase.FindAssets("t:Script",
                new string[] { sourcePath }).Length != 0)
            {
                //弹出确认弹窗
                if (!EditorUtility.DisplayDialog("提示", string.Format(
                    "是否确认将文件夹{0}移动至{1}",
                    sourcePath, destinationPath), "确认", "取消"))
                    return AssetMoveResult.FailedMove;
            }
        }
        return AssetMoveResult.DidNotMove;
    }
}

3. 自动资源优化

public class TextureOptimizer : AssetModificationProcessor
{
    static string[] OnWillSaveAssets(string[] paths)
    {
        foreach (var path in paths.Where(p => p.EndsWith(".png")))
        {
            Texture2D tex = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
            if (tex.width > 1024) 
            {
                Debug.Log($"优化大纹理: {path}");
                // 调用纹理压缩API...
            }
        }
        return paths;
    }
}

使用注意事项

  1. 脚本位置

    • 必须放在 Editor 文件夹内
    • 建议路径:Assets/Editor/AssetProcessors/
  2. 性能考量

    • 避免在回调中执行耗时操作
    • 批量操作时使用缓存机制
    • 使用 EditorApplication.delayCall 延迟非关键任务
  3. 错误处理

    static void OnWillCreateAsset(string path)
    {
        try {
            // 处理逻辑
        }
        catch (Exception ex) {
            Debug.LogError($"处理失败: {ex.Message}");
        }
    }
    
  4. 多处理器协调

    • Unity 按脚本文件名顺序执行处理器
    • 使用 [InitializeOnLoad] 控制初始化顺序

高级应用场景

1. 版本控制系统集成

static AssetDeleteResult OnWillDeleteAsset(string path, RemoveAssetOptions options)
{
    if (VCS.IsFileLocked(path)) {
        Debug.LogWarning($"文件被锁定: {path}");
        return AssetDeleteResult.FailedDelete;
    }
    return AssetDeleteResult.DidDelete;
}

2. 自动化资源依赖管理

static void OnWillCreateAsset(string path)
{
    if (path.EndsWith(".prefab")) {
        GameObject prefab = // 加载预制体
        AutoAssignMaterials(prefab);
    }
}

3. 资源变更审计系统

static string[] OnWillSaveAssets(string[] paths)
{
    foreach (var path in paths) {
        AuditSystem.LogChange(path, "SAVE");
    }
    return paths;
}

最佳实践指南

  1. 单一职责原则

    • 每个处理器只处理特定类型资源
    • 分离创建、保存、删除逻辑
  2. 条件过滤优化

    static void OnWillCreateAsset(string path)
    {
        if (!path.EndsWith(".mat")) return; // 只处理材质
        // ...
    }
    
  3. 用户配置支持

    [CreateAssetMenu(menuName = "Tools/ProcessorConfig")]
    public class ProcessorConfig : ScriptableObject
    {
        public bool enableAutoHeader = true;
    }
    
  4. 编辑器菜单控制

    [MenuItem("Tools/Toggle Auto Header")]
    static void ToggleProcessor()
    {
        EditorPrefs.SetBool("AutoHeaderEnabled", 
            !EditorPrefs.GetBool("AutoHeaderEnabled", true));
    }
    

常见问题解决方案

问题:处理器未被调用

  • 检查点
    1. 脚本是否在 Editor 文件夹
    2. 是否有编译错误
    3. Unity 版本是否兼容

问题:资源操作卡顿

  • 优化方案
    static string[] OnWillSaveAssets(string[] paths)
    {
        if (paths.Length > 20) // 批量操作时跳过
            return paths;
        
        // 处理逻辑...
    }
    

问题:跨平台兼容性

  • 路径处理
    string fullPath = Path.Combine(Application.dataPath, "../", path);
    

总结

AssetModificationProcessor 是 Unity 编辑器扩展的利器,通过它开发者可以:

  1. 自动化重复性资源管理任务
  2. 强制团队资源规范
  3. 实现高级资源处理流水线
  4. 构建自定义开发工作流

掌握此接口能显著提升项目开发效率,特别适合需要严格资源管理规范的团队项目。使用时需注意性能影响和错误处理,合理规划处理器逻辑,可大幅提升团队协作效率。


网站公告

今日签到

点亮在社区的每一天
去签到