Unity编辑器扩展之Project视图扩展

news2025/5/18 8:38:38

内容将会持续更新,有错误的地方欢迎指正,谢谢!
 

Unity编辑器扩展之Project视图扩展
     
TechX 坚持将创新的科技带给世界!

拥有更好的学习体验 —— 不断努力,不断进步,不断探索
TechX —— 心探索、心进取!

助力快速掌握 Project视图 编辑器扩展

为初学者节省宝贵的学习时间,避免困惑!



文章目录

  • 一、EditorApplication.projectChanged 之自动更新资源依赖报告
  • 二、EditorApplication.projectWindowItemOnGUI 之标记资源大小
  • 三、UnityEditor.AssetModificationProcessor 之资源修改处理器
    • 3.1、OnWillCreateAsset 之自动添加资源模板
    • 3.2、OnWillSaveAssets
    • 3.3、OnWillMoveAsset
    • 3.4、OnWillDeleteAsset


一、EditorApplication.projectChanged 之自动更新资源依赖报告


使用 EditorApplication.projectChanged 可以在项目资源发生变化时自动执行一些功能。下面展示如何使用这个事件在Unity项目中实现一个简单但实用的功能:自动更新资源依赖报告。

当项目资源变化时自动生成一份资源依赖报告,列出哪些资源被哪些其他资源依赖。这在进行资源优化或清理时非常有用。

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

[InitializeOnLoad]
public static class DependencyReportGenerator
{
    private const string ReportPath = "Assets/DependencyReport.txt";

    static DependencyReportGenerator()
    {
        EditorApplication.projectChanged += OnProjectChanged;
    }

    private static void OnProjectChanged()
    {
        Debug.Log("项目资源发生变化,正在生成依赖报告...");

        Dictionary<string, List<string>> dependencyMap = GenerateDependencys();

        GenerateReport(dependencyMap);

        Debug.Log("依赖报告生成完毕。");
    }

    /// <summary>
    /// 生成依赖项
    /// </summary>
    private static Dictionary<string, List<string>> GenerateDependencys()
    {
        string[] allAssetGuids = AssetDatabase.FindAssets("");

        Dictionary<string, List<string>> dependencyMap = new Dictionary<string, List<string>>();

        foreach (string guid in allAssetGuids)
        {
            string assetPath = AssetDatabase.GUIDToAssetPath(guid);
            string[] dependencies = AssetDatabase.GetDependencies(assetPath, false);

            foreach (string dependency in dependencies)
            {
                if (!dependencyMap.ContainsKey(dependency))
                {
                    dependencyMap[dependency] = new List<string>();
                }

                dependencyMap[dependency].Add(assetPath);
            }
        }

        return dependencyMap;
    }

    /// <summary>
    /// 生成报告
    /// </summary>
    private static void GenerateReport(Dictionary<string, List<string>> dependencyMap)
    {
        using (StreamWriter writer = new StreamWriter(ReportPath))
        {
            foreach (var kvp in dependencyMap)
            {
                writer.WriteLine($"资源:{kvp.Key}");
                writer.WriteLine("被以下资源依赖:");

                foreach (string dependent in kvp.Value)
                {
                    writer.WriteLine($" - {dependent}");
                }

                writer.WriteLine();
            }
        }
    }
}

资源依赖报告列出了每个资源被哪些其他资源依赖,帮助开发者了解资源之间的关系。

生成的资源依赖报告文件存储在 Assets/DependencyReport.txt 中。

在这里插入图片描述



二、EditorApplication.projectWindowItemOnGUI 之标记资源大小


EditorApplication.projectWindowItemOnGUI 是一个非常实用的 API,它允许你在 Unity 的 Project 窗口中自定义显示项目资源的图标、标签或其他信息。通过这个方法,可以实现一些方便开发者查看和管理资源的功能。

我们可以通过 EditorApplication.projectWindowItemOnGUI 实现一个功能:在 Project 窗口中直接显示每个资源的文件大小。这在管理大型项目时非常有用,可以帮助开发者快速识别占用空间较大的资源并进行优化。

using UnityEditor;
using UnityEngine;
using System.IO;

[InitializeOnLoad]
public static class AssetSizeDisplay
{
    static AssetSizeDisplay()
    {
        EditorApplication.projectWindowItemOnGUI += OnProjectWindowItemOnGUI;
    }

    private static void OnProjectWindowItemOnGUI(string guid, Rect selectionRect)
    {
        // 获取资源路径
        string assetPath = AssetDatabase.GUIDToAssetPath(guid);

        // 仅处理文件,不处理文件夹
        if (File.Exists(assetPath))
        {
            // 获取文件大小
            long fileSize = new FileInfo(assetPath).Length;
            string fileSizeStr = GetReadableFileSize(fileSize);

            // 根据文件大小设置颜色
            Color labelColor = GetColorByFileSize(fileSize);

            // 在资源右侧显示文件大小
            Rect sizeRect = new Rect(selectionRect.xMax - 50, selectionRect.y, 75, selectionRect.height);
            EditorGUI.DrawRect(selectionRect, labelColor * 0.2f); // 背景色(较浅)
            EditorGUI.LabelField(sizeRect, fileSizeStr, new GUIStyle(EditorStyles.label) { normal = { textColor = labelColor } });
        }
    }

    /// <summary>
    /// 将文件大小转换为易读的格式
    /// </summary>
    /// <param name="size"></param>
    /// <returns></returns>
    private static string GetReadableFileSize(long size)
    {
        string[] sizes = { "B", "KB", "MB", "GB" };
        int order = 0;
        while (size >= 1024 && order < sizes.Length - 1)
        {
            order++;
            size = size / 1024;
        }
        return $"{size:0.#} {sizes[order]}";
    }

    /// <summary>
    /// 根据文件大小返回不同的颜色
    /// </summary>
    /// <param name="size"></param>
    /// <returns></returns>
    private static Color GetColorByFileSize(long size)
    {
        if (size > 100 * 1024 * 1024) // 大于 100MB
            return Color.red;
        if (size > 10 * 1024 * 1024)  // 大于 10MB
            return new Color(1f, 0.5f, 0f); // 橙色
        if (size > 1 * 1024 * 1024)   // 大于 1MB
            return Color.yellow;

        return Color.green;            // 小于 1MB
    }
}

在 Project 窗口中,每个文件资源的右侧都会显示其文件大小。这样,开发者可以在不打开资源详情的情况下,快速了解各资源的占用空间,从而有助于进行优化和管理。并且根据文件大小用不同颜色标记资源。

在这里插入图片描述



三、UnityEditor.AssetModificationProcessor 之资源修改处理器


UnityEditor.AssetModificationProcessor 是 Unity 编辑器提供的一个抽象类,它允许开发者在编辑器中拦截和处理与资源(Assets)相关的事件。

通过继承和实现这个类,开发者可以编写自定义逻辑来响应资源的创建、保存、移动和删除等操作。此类在需要对资源操作进行管理、限制或自动化时非常有用。

public class AssetEventEditor : UnityEditor.AssetModificationProcessor
{
    //监听"资源即将被创建"事件
    public static void OnWillCreateEdit(string path)
    {
        Debug.LogFormat("创建资源的路径:{0}", path);
    }

    //监听"资源即将被保存"事件
    public static string[] OnWillSaveAssets(string[] paths) {
    
        Debug.LogFormat("保存资源的路径:{0}",string.Join(",",paths));
        return paths;
    }

    //监听"资源即将被移动"事件  DidNotMove表示可以移动,DidMove表示不可以移动
    public static AssetMoveResult OnWillMoveAsset(string oldPath,string newPath) {
      
        Debug.LogFormat("资源从路径{0}移动到路径{1}", oldPath,newPath);
        return AssetMoveResult.DidNotMove;
    }
    
    //监听"资源即将被删除"事件 DidNotDelete表示可以移动,DidDelete表示不可以移动
    public static AssetDeleteResult OnWillDeleteAsset(string assetPath) {
      
        Debug.LogFormat("资源从路径{0}删除", assetPath);
        return AssetDeleteResult.DidNotDelete;
    }

3.1、OnWillCreateAsset 之自动添加资源模板


OnWillCreateAsset 方法在 Unity 中用于拦截和处理即将创建的资源事件。

当一个新的资源(如脚本、预制件、纹理等)被创建时,OnWillCreateAsset 方法会被调用。

这个方法可以让你在资源创建之前执行一些自定义操作。

public static void OnWillCreateAsset(string path)
{
    path = path.Replace(".meta", "");
    if (path.EndsWith(".cs"))
    {
        string fullPath = Path.Combine(Directory.GetCurrentDirectory(), path);
        string fileContent = File.ReadAllText(fullPath);

        // 插入默认命名空间
        fileContent = fileContent.Replace("#SCRIPTNAME#", Path.GetFileNameWithoutExtension(path));

        fileContent = string.Join("\n", fileContent.Split('\n').Select(item => "\t" + item));

        fileContent = "using UnityEngine;\n\nnamespace MyNamespace\n{\n" + fileContent + "\n}".TrimStart('\t');

        File.WriteAllText(fullPath, fileContent);
        AssetDatabase.Refresh();
        Debug.LogFormat("创建脚本时自动添加了命名空间:{0}", path);
    }
}

在这个例子中,OnWillCreateAsset 方法在创建脚本的时候被调用,它被用来为新创建的 C# 脚本文件添加命名空间并格式化代码。这种自动化操作可以提高代码的一致性和开发效率。

在这里插入图片描述


3.2、OnWillSaveAssets


OnWillSaveAssets 在Unity中用于在保存资产(例如场景、预制体)之前执行特定的操作。

这个方法可以帮助你在资产保存之前进行自定义的检查和处理。通过在这个方法中执行适当的逻辑,可以确保资产的质量和一致性,从而提高开发效率并减少潜在问题。

public static string[] OnWillSaveAssets(string[] paths)
    {
        foreach (string path in paths)
        {
            if (path.EndsWith(".prefab") || path.EndsWith(".unity"))
            {
                CheckForMissingReferences(path);
            }
        }
        return paths;
    }

    private static void CheckForMissingReferences(string path)
    {
        // 加载资源对象,处理预制件或场景文件
        Object asset = AssetDatabase.LoadAssetAtPath<Object>(path);

        // 检查场景文件
        if (asset is SceneAsset)
        {
            Scene scene = EditorSceneManager.OpenScene(path, OpenSceneMode.Additive);
            CheckSceneForMissingReferences(scene);
        }
        // 检查预制件
        else if (asset is GameObject go)
        {
            CheckGameObjectForMissingReferences(go, path);
        }
    }

    private static void CheckSceneForMissingReferences(Scene scene)
    {
        foreach (GameObject rootObj in scene.GetRootGameObjects())
        {
            CheckGameObjectForMissingReferences(rootObj, scene.path);
        }
    }

    private static void CheckGameObjectForMissingReferences(GameObject go, string path)
    {
        if (PrefabUtility.IsPartOfAnyPrefab(go) && PrefabUtility.GetCorrespondingObjectFromSource(go) == null)
        {
            Debug.LogError($"预制体引用丢失 对象:{GetGameObjectPath(go)},路径: {path}", go);
        }

        foreach (Component component in go.GetComponentsInChildren<Component>(true))
        {
            if (component == null)
            {
                Debug.LogError($"脚本引用丢失 对象:{GetGameObjectPath(go)},路径: {path}", go);
            }
        }
    }

    private static string GetGameObjectPath(GameObject go)
    {
        if (go.transform.parent == null) return go.name;
      
        return GetGameObjectPath(go.transform.parent.gameObject) + "/" + go.name;
    }

在这个例子中,OnWillSaveAssets方法在在保存场景和预制体时检查是否存在丢失的脚本和预制体引用,并在控制台输出相关警告。

3.3、OnWillMoveAsset


OnWillMoveAsset 在 Unity 中用于当资源(如脚本、预制件等)即将被移动到新路径时调用。

它允许开发者在移动资源前执行一些自定义逻辑,并决定是否允许资源移动。

//监听"资源即将被移动"事件
    public static AssetMoveResult OnWillMoveAsset(string oldPath, string newPath)
{
    UpdateScriptPaths(oldPath, newPath);
    return AssetMoveResult.DidNotMove; // 允许移动
}
private static void UpdateScriptPaths(string oldPath, string newPath)
{
    // 查找所有脚本文件并更新路径
    string[] scripts = AssetDatabase.FindAssets("t:Script");
    foreach (string scriptGUID in scripts)
    {
        string scriptPath = AssetDatabase.GUIDToAssetPath(scriptGUID);
        string scriptContent = File.ReadAllText(scriptPath);
        
        if (scriptContent.Contains(oldPath))
        {
            scriptContent = scriptContent.Replace(oldPath, newPath);
            File.WriteAllText(scriptPath, scriptContent);
            AssetDatabase.Refresh();
            Debug.LogFormat("更新脚本中的资源路径: {0}", scriptPath);
        }
    }
}

当资源移动到新位置时,项目中的脚本可能依赖于该资源的路径。通过在 OnWillMoveAsset 方法中更新脚本中的路径引用,可以确保项目正常运行,避免路径失效导致的错误。

3.4、OnWillDeleteAsset


OnWillDeleteAsset 在 Unity 中用于在资源(如脚本、预制件、材质等)即将被删除时进行拦截和处理。

通过这个方法,开发者可以在资源被删除前执行自定义逻辑,比如弹出确认对话框、记录日志,甚至阻止资源删除。

public static AssetDeleteResult OnWillDeleteAsset(string assetPath, RemoveAssetOptions assetOptions)
{
    if (assetPath.StartsWith("Assets/ImportantAssets/"))
    {
        Debug.Log(assetPath);
        if (!EditorUtility.DisplayDialog("警告", $"你确定要删除重要资源 {assetPath} 吗?", "确定", "取消"))
        {
            Debug.LogWarning($"已取消删除重要资源:{assetPath}");
            return AssetDeleteResult.DidDelete; // 阻止删除
        }
    }

    Debug.LogFormat("资源 {0} 被删除", assetPath);
    return AssetDeleteResult.DidNotDelete; // 允许删除
}

通过自定义逻辑,开发者可以确保重要资源不会被轻易删除,并在删除前执行必要的检查和确认。这个方法对于项目管理和资源保护非常有用。

在这里插入图片描述





TechX —— 心探索、心进取!

每一次跌倒都是一次成长

每一次努力都是一次进步


END
感谢您阅读本篇博客!希望这篇内容对您有所帮助。如果您有任何问题或意见,或者想要了解更多关于本主题的信息,欢迎在评论区留言与我交流。我会非常乐意与大家讨论和分享更多有趣的内容。
如果您喜欢本博客,请点赞和分享给更多的朋友,让更多人受益。同时,您也可以关注我的博客,以便及时获取最新的更新和文章。
在未来的写作中,我将继续努力,分享更多有趣、实用的内容。再次感谢大家的支持和鼓励,期待与您在下一篇博客再见!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2064636.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

河南萌新联赛2024第(六)场:郑州大学(补题ABCDFGIL)

文章目录 河南萌新联赛2024第&#xff08;六&#xff09;场&#xff1a;郑州大学A 装备二选一&#xff08;一&#xff09;简单介绍&#xff1a;思路&#xff1a;代码&#xff1a; B 百变吗喽简单介绍&#xff1a;思路&#xff1a;代码&#xff1a; C 16进制世界简单介绍&#x…

第二十七节、人物可互动标识

一、多个场景同时存在 方法&#xff1a;将另一个场景拖拽进 当前场景中 这样在一个场景中保存物体&#xff0c;另一个场景切换即可 创建一个场景名为上图&#xff08;这是一个持久化的场景&#xff09; 被激活的场景是粗体字的 二、代码 使用第二个代码获得player的子物体 …

uniapp在线下载安装包更新app以及热更新

首先用getSystemInfo判断平台、 再通过json文件模拟接口 判断版本号是否一致 不一致则下载服务器apk进行更新 外加网络波动导致失败重新下载更新包 uni.getSystemInfo({success: function (e) {// #ifndef H5// 获取手机系统版本const system e.system.toLowerCase();const pl…

《黑神话:悟空》解锁+35项修改器,开启上帝模式!

哈喽&#xff0c;各位小伙伴们好&#xff0c;我是给大家带来各类黑科技与前沿资讯的小武。 8 月 20 日&#xff0c;国产 3A 大作《黑神话&#xff1a;悟空》闪亮登场&#xff01;这是一款由中国游戏开发商游戏科学开发的动作角色扮演游戏&#xff0c;此前在研发阶段就备受关注…

Python 使用 matplotlib 显示图像

如果没有安装 matplotlib 需要先安装&#xff1a; pip install matplotlib一、读取图片并显示 import matplotlib.pyplot as pltimage_path "/Users/AlanWang4523/Desktop/Debug/files/image.png" image_array plt.imread(image_path)plt.figure("ImageShow…

会声会影作为视屏制作软件如何?会声会影最新免费版

二、核心功能与特点 拖放式编辑&#xff1a;会声会影2024提供了拖放式标题、转场、覆叠和滤镜功能&#xff0c;使得视频编辑变得更加直观和高效。 色彩分级与动态分屏&#xff1a;软件支持色彩分级功能&#xff0c;可以对视频进行精细的色彩调整。同时&#xff0c;动态分屏功能…

STM32通用定时器,端口复用和重映射

STM32定时器是一种内置在STM32微控制器中的硬件模块&#xff0c;用于测量和控制时间。它具有高精度、可配置性和灵活性的特点&#xff0c;能够支持多种不同的工作模式和应用场景。以下是对STM32定时器的详细讲解&#xff1a; 一、定时器的基本构成 STM32定时器主要由以下几个…

内存管理————基础理解

目录 我们先看以下代码和内存分布图 对一些名词的解释说明&#xff1a; 题目 答案 问题解释&#xff1a; C语言中动态内存管理方式 C语言中动态内存管理方式&#xff1a;malloc/calloc/realloc/free 这里提一下要注意的点 C内存管理方式 基本内容 new/delete操作内置…

常用API:object

文章目录 Object类toString()方法equals()方法总结其他方法 黑马学习笔记 Object类 是所有类的父类&#xff0c;所有的类都默认继承Object类。Java中所有的类的对象都可以直接使用Object类提供的一些方法。 toString()方法 equals()方法 默认是判断两个对象的地址 也是判断…

MATLAB-疲劳检测

首先&#xff0c;我们需要解决一个问题&#xff0c;什么样可以视为疲劳&#xff1f; 频繁的眨眼/眨一次眼所用时间很长 不停的打哈欠 不停的点头 通过分析&#xff0c;我们得到了检测疲劳的三个标准&#xff1a;眨眼&#xff0c;打哈欠&#xff0c;头部姿态。 这三个标准可以…

OpenCV findTours函数及其用法

OpenCV findTours函数主要用以寻找图像中物体的轮廓&#xff0c;其原型如下&#xff1a; indTours 函数参数&#xff1a; Image 输入图像&#xff0c;需8位单通道图像。非零像素被视为1。零像素保持为0&#xff0c;因 此图 像被视为 二进制。您可以使用co…

【数据分享】《全国能源-分行业煤油消费总量》(2000-2020年)

而今天要限时免费分享的数据就是2000-2020年间出版的《全国能源-分行业煤油消费总量》并以多格式提供免费下载。&#xff08;无需分享朋友圈即可获取&#xff09; 数据介绍 在过去的二十年里&#xff0c;中国作为全球能源消费的重要力量&#xff0c;其能源结构的变化不仅影…

基于x86 平台opencv的图像采集和seetaface6的图像质量评估功能

目录 一、概述二、环境要求2.1 硬件环境2.2 软件环境三、开发流程3.1 编写测试3.2 配置资源文件3.2 验证功能一、概述 本文档是针对x86 平台opencv的图像采集和seetaface6的图像质量评估功能,opencv通过摄像头采集视频图像,将采集的视频图像送给seetaface6的图像质量评估模块…

21.1 基于Netty实现聊天

21.1 基于Netty实现聊天 一. 章节概述二. `Netty`介绍三. 阻塞与非阻塞1. 阻塞与非阻塞简介2. BIO同步阻塞3. NIO同步非阻塞4. AIO异步非阻塞IO5. 异步阻塞IO(用的极少)6. 总结四. Netty三种线程模型1. 单线程模型2. 多线程模型3. 主从线程模型五. 构建Netty服务器************…

DDL——三范式与表约束

目录 一、三大范式 1.范式的定义 2.第一范式 3.第二范式 4.第三范式 二、表约束 1.约束的定义 2.非空约束&#xff08;not null&#xff09; 3.唯一性约束&#xff08;unique&#xff09; 4.主键约束&#xff08;primary key&#xff09; 5.外键约束&#xff08;fo…

可集成多模型的机器人开发框架 dora:让机器人编程走向大众

作者 | Annie Xu 责编 | 何苗 出品 | GOSIM 开源创新汇 C 和 C是机器人编程中常用的编程语言&#xff0c;但学起来存在一定难度。那些对机器人感兴趣&#xff0c;但没有精力花费数周时间学习 C 和 C编程的用户只能望而却步。 为了让机器人技术变得更简单&#xff0c;陶海轩&a…

AWS SAM CLI 备忘单!

安装 AWS SAM CLI brew tap aws/tap brew 安装 aws-sam-cli 验证安装 $ sam --version 升级 SAM $ brew upgrade aws-sam-cli 您需要 AWS 凭证才能在 AWS 上工作。 构建并部署简单应用程序 $ sam init→ 下载示例应用程序 $ sam build→ 构建您的应用程序 $ sam deploy --guid…

机器学习:决策树回归树实现

1、决策树&#xff1a; 是一种树形结构&#xff0c;用于通过一系列的是非问题来预测目标值。在决策树回归中&#xff0c;树的叶子节点代表预测的连续值。 2、数据准备&#xff1a; 收集数据集&#xff0c;并对其进行清洗和预处理。 将数据集分为特征&#xff08;X&#xff09;…

git-20240822

目录 初始化仓库 Git init Git init project --bare 查看提交的记录 git log --prettyoneline 查看当前git远程库地址 git remote -v 查看详细提交记录 git log 撤出暂存区的文件 git reset HEAD file(.代表全部文件&#xff09; 提交数据到远程仓库 git config --global push.…

4.6算法之贪心_702:Crossing River

题目 702:Crossing River 总时间限制: 1000ms 内存限制: 65536kB 描述 A group of N people wishes to go across a river with only one boat, which can at most carry two persons. Therefore some sort of shuttle arrangement must be arranged in order to row the boat…