Unity AssetModificationProcessor 全面解析
AssetModificationProcessor
是 Unity 编辑器扩展的核心接口之一,它允许开发者在资源生命周期关键节点插入自定义逻辑。这个强大的工具可以实现自动化资源管理、规范团队工作流程、提升开发效率。
核心功能与作用
AssetModificationProcessor
提供了一系列回调方法,在以下资源操作时触发:
关键方法详解
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;
}
}
使用注意事项
脚本位置:
- 必须放在
Editor
文件夹内 - 建议路径:
Assets/Editor/AssetProcessors/
- 必须放在
性能考量:
- 避免在回调中执行耗时操作
- 批量操作时使用缓存机制
- 使用
EditorApplication.delayCall
延迟非关键任务
错误处理:
static void OnWillCreateAsset(string path) { try { // 处理逻辑 } catch (Exception ex) { Debug.LogError($"处理失败: {ex.Message}"); } }
多处理器协调:
- 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;
}
最佳实践指南
单一职责原则:
- 每个处理器只处理特定类型资源
- 分离创建、保存、删除逻辑
条件过滤优化:
static void OnWillCreateAsset(string path) { if (!path.EndsWith(".mat")) return; // 只处理材质 // ... }
用户配置支持:
[CreateAssetMenu(menuName = "Tools/ProcessorConfig")] public class ProcessorConfig : ScriptableObject { public bool enableAutoHeader = true; }
编辑器菜单控制:
[MenuItem("Tools/Toggle Auto Header")] static void ToggleProcessor() { EditorPrefs.SetBool("AutoHeaderEnabled", !EditorPrefs.GetBool("AutoHeaderEnabled", true)); }
常见问题解决方案
问题:处理器未被调用
- 检查点:
- 脚本是否在 Editor 文件夹
- 是否有编译错误
- Unity 版本是否兼容
问题:资源操作卡顿
- 优化方案:
static string[] OnWillSaveAssets(string[] paths) { if (paths.Length > 20) // 批量操作时跳过 return paths; // 处理逻辑... }
问题:跨平台兼容性
- 路径处理:
string fullPath = Path.Combine(Application.dataPath, "../", path);
总结
AssetModificationProcessor
是 Unity 编辑器扩展的利器,通过它开发者可以:
- 自动化重复性资源管理任务
- 强制团队资源规范
- 实现高级资源处理流水线
- 构建自定义开发工作流
掌握此接口能显著提升项目开发效率,特别适合需要严格资源管理规范的团队项目。使用时需注意性能影响和错误处理,合理规划处理器逻辑,可大幅提升团队协作效率。