以编程方式设置并保存与导入资源关联的图标

2024-01-04

我有一些自动生成的数据被导出到我的 Unity 项目中。为了帮助我,我想为这些资产分配一个自定义图标以清楚地识别它们。这当然可以通过编辑器本身实现,但理想情况下我希望在导入时自动发生。

为此,我编写了一个 AssetPostProcessor 来为我处理这个问题。在下面的示例中(以 MonoScript 为例,但也可以应用于任何类型的资源),所有新导入的脚本都将分配有 MyFancyIcon 图标。此更新在脚本资源本身以及检查器中的 MonoBehaviours 上都可见。

using UnityEngine;
using UnityEditor;
using System.Reflection;

public class IconAssignmentPostProcessor : AssetPostprocessor
{
    static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
    {
        Texture2D icon = AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/Iconfolder/MyFancyIcon.png");
        foreach (string asset in importedAssets)
        {
            MonoScript script = AssetDatabase.LoadAssetAtPath<MonoScript>(asset);
            if(script != null)
            {
                PropertyInfo inspectorModeInfo = typeof(SerializedObject).GetProperty("inspectorMode", BindingFlags.NonPublic | BindingFlags.Instance);
                SerializedObject serializedObject = new SerializedObject(script);
                inspectorModeInfo.SetValue(serializedObject, InspectorMode.Debug, null);
                SerializedProperty iconProperty = serializedObject.FindProperty("m_Icon");
                iconProperty.objectReferenceValue = icon;
                serializedObject.ApplyModifiedProperties();
                serializedObject.Update();

                EditorUtility.SetDirty(script);
            }
        }

        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }    
}

除了一个问题之外,它工作得很好。关闭项目并重新打开它时不会保存更新。据我所知,要么EditorUtility.SetDirty(script);调用应该解决这个问题,或者至少AssetDatabase.SaveAssets(); call.

然而,看看手动分配图标(有效)和以编程方式分配图标之间的区别,有一个icon与资产关联的元文件中的字段在手动分配图标时会被设置,但在我的脚本案例中不会设置。 (在脚本化的情况下,元文件甚至没有更新)

那么什么给出呢?当我(显然)只更改元数据时,我是否必须做任何事情?有什么简单的事情我忽略了吗?


对该代码进行了实验并得出结论,这是一个错误。已与 Unity 联系,这是他们的回复:

目前,这是一个已提交的错误,我们的开发团队正在 调查它。看来这个错误的发生似乎是因为 AssetDatabes.SaveAssets() 不保存更改。

解决方法是手动执行此操作。

调用 OnPostprocessAllAssets 时处理和保存数据:

1.创建一个 Json 文件设置,如果该设置不存在,该设置将保存该设置。

2.When OnPostprocessAllAssets被称为,加载旧的 Json 文件设置。

4.将精美的图标应用于资产。

5.循环加载的Json文件设置并检查它是否包含来自importedAssets范围。

如果它包含加载的文件,请修改该设置并保存。如果没有,请将其添加到列表中然后保存。

6.检查资产是否importedAssets硬盘上不存在File.Exists。如果不存在,请将其从加载的 Json 文件设置列表中删除,然后保存。

Unity 加载时自动重新应用精美图标:

1.添加一个静态构造函数IconAssignmentPostProcessor班级。当编辑器加载时以及当OnPostprocessAllAssets被调用。

2调用构造函数时,创建一个 Json 文件设置,如果该设置不存在,则该设置将保存该设置。

3.加载旧的Json文件设置。

4通过循环加载的 Json 文件来重新应用精美的图标。

5检查加载的 Json 文件是否仍有不在驱动器上的资源。如果是这样,请从列表中删除该资产,然后保存它。

下面是新内容IconAssignmentPostProcessor脚本应该如下所示:

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

public class IconAssignmentPostProcessor : AssetPostprocessor
{
    // Called when Editor Starts
    static IconAssignmentPostProcessor()
    {
        prepareSettingsDir();
        reloadAllFancyIcons();
    }

    private static string settingsPath = Application.dataPath + "/FancyIconSettings.text";
    private static string fancyIconPath = "Assets/Iconfolder/MyFancyIcon.png";

    private static bool firstRun = true;

    static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
    {
        prepareSettingsDir();

        //Load old settings 
        FancyIconSaver savedFancyIconSaver = LoadSettings();


        Texture2D icon = AssetDatabase.LoadAssetAtPath<Texture2D>(fancyIconPath);

        for (int j = 0; j < importedAssets.Length; j++)
        {
            string asset = importedAssets[j];

            MonoScript script = AssetDatabase.LoadAssetAtPath<MonoScript>(asset);
            if (script != null)
            {
                //Apply fancy Icon
                ApplyIcon(script, icon);

                //Process each asset 
                processFancyIcon(savedFancyIconSaver, fancyIconPath, asset, pathToGUID(asset));
            }
        }

        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }


    public static string pathToGUID(string path)
    {
        return AssetDatabase.AssetPathToGUID(path);
    }

    public static string guidToPath(string guid)
    {
        return AssetDatabase.GUIDToAssetPath(guid);
    }

    public static void processFancyIcon(FancyIconSaver oldSettings, string fancyIconPath, string scriptPath, string scriptGUID)
    {
        int matchIndex = -1;

        if (oldSettings == null)
        {
            oldSettings = new FancyIconSaver();
        }

        if (oldSettings.fancyIconData == null)
        {
            oldSettings.fancyIconData = new List<FancyIconData>();
        }

        FancyIconData fancyIconData = new FancyIconData();
        fancyIconData.fancyIconPath = fancyIconPath;
        fancyIconData.scriptPath = scriptPath;
        fancyIconData.scriptGUID = scriptGUID;

        //Check if this guid exist in the List already. If so, override it with the match index
        if (containsGUID(oldSettings, scriptGUID, out matchIndex))
        {
            oldSettings.fancyIconData[matchIndex] = fancyIconData;
        }
        else
        {
            //Does not exist, add it to the existing one
            oldSettings.fancyIconData.Add(fancyIconData);
        }

        //Save the data
        SaveSettings(oldSettings);

        //If asset does not exist, delete it from the json settings
        for (int i = 0; i < oldSettings.fancyIconData.Count; i++)
        {
            if (!assetExist(scriptPath))
            {
                //Remove it from the List then save the modified List
                oldSettings.fancyIconData.RemoveAt(i);
                SaveSettings(oldSettings);
                Debug.Log("Asset " + scriptPath + " no longer exist. Deleted it from JSON Settings");
                continue; //Continue to the next Settings in the List
            }
        }
    }

    //Re-loads all the fancy icons
    public static void reloadAllFancyIcons()
    {
        if (!firstRun)
        {
            firstRun = false;
            return; //Exit if this is not first run
        }

        //Load old settings 
        FancyIconSaver savedFancyIconSaver = LoadSettings();

        if (savedFancyIconSaver == null || savedFancyIconSaver.fancyIconData == null)
        {
            Debug.Log("No Previous Fancy Icon Settings Found!");
            return;//Exit
        }


        //Apply Icon Changes
        for (int i = 0; i < savedFancyIconSaver.fancyIconData.Count; i++)
        {
            string asset = savedFancyIconSaver.fancyIconData[i].scriptPath;

            //If asset does not exist, delete it from the json settings
            if (!assetExist(asset))
            {
                //Remove it from the List then save the modified List
                savedFancyIconSaver.fancyIconData.RemoveAt(i);
                SaveSettings(savedFancyIconSaver);
                Debug.Log("Asset " + asset + " no longer exist. Deleted it from JSON Settings");
                continue; //Continue to the next Settings in the List
            }

            string tempFancyIconPath = savedFancyIconSaver.fancyIconData[i].fancyIconPath;

            Texture2D icon = AssetDatabase.LoadAssetAtPath<Texture2D>(tempFancyIconPath);
            MonoScript script = AssetDatabase.LoadAssetAtPath<MonoScript>(asset);
            if (script == null)
            {
                continue;
            }

            Debug.Log(asset);
            ApplyIcon(script, icon);
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }

    private static void ApplyIcon(MonoScript script, Texture2D icon)
    {
        PropertyInfo inspectorModeInfo = typeof(SerializedObject).GetProperty("inspectorMode", BindingFlags.NonPublic | BindingFlags.Instance);
        SerializedObject serializedObject = new SerializedObject(script);
        inspectorModeInfo.SetValue(serializedObject, InspectorMode.Debug, null);
        SerializedProperty iconProperty = serializedObject.FindProperty("m_Icon");
        iconProperty.objectReferenceValue = icon;
        serializedObject.ApplyModifiedProperties();
        serializedObject.Update();
        EditorUtility.SetDirty(script);
        Debug.Log("Applied Fancy Icon to: " + script.name);
    }

    //Creates the Settings File if it does not exit yet
    private static void prepareSettingsDir()
    {
        if (!File.Exists(settingsPath))
        {
            File.Create(settingsPath);
        }
    }

    public static void SaveSettings(FancyIconSaver fancyIconSaver)
    {
        try
        {
            string jsonData = JsonUtility.ToJson(fancyIconSaver, true);
            Debug.Log("Data: " + jsonData);

            byte[] jsonByte = Encoding.ASCII.GetBytes(jsonData);
            File.WriteAllBytes(settingsPath, jsonByte);
        }
        catch (Exception e)
        {
            Debug.Log("Settings not Saved: " + e.Message);
        }
    }

    public static FancyIconSaver LoadSettings()
    {
        FancyIconSaver loadedData = null;
        try
        {
            byte[] jsonByte = File.ReadAllBytes(settingsPath);
            string jsonData = Encoding.ASCII.GetString(jsonByte);
            loadedData = JsonUtility.FromJson<FancyIconSaver>(jsonData);
            return loadedData;
        }
        catch (Exception e)
        {
            Debug.Log("No Settings Loaded: " + e.Message);
        }
        return loadedData;
    }

    public static bool containsGUID(FancyIconSaver fancyIconSaver, string guid, out int matchIndex)
    {
        matchIndex = -1;

        if (fancyIconSaver == null || fancyIconSaver.fancyIconData == null)
        {
            Debug.Log("List is null");
            return false;
        }

        for (int i = 0; i < fancyIconSaver.fancyIconData.Count; i++)
        {
            if (fancyIconSaver.fancyIconData[i].scriptGUID == guid)
            {
                matchIndex = i;
                return true;
            }
        }
        return false;
    }

    public static bool assetExist(string path)
    {
        return File.Exists(path);
    }

    [Serializable]
    public class FancyIconSaver
    {
        public List<FancyIconData> fancyIconData;
    }

    [Serializable]
    public class FancyIconData
    {
        public string fancyIconPath;
        public string scriptPath;
        public string scriptGUID;
    }
}

当 Unity 重新启动时,这应该会保留精美的图标。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

以编程方式设置并保存与导入资源关联的图标 的相关文章

  • ROWNUM 的 OracleType 是什么

    我试图参数化所有现有的 sql 但以下代码给了我一个问题 command CommandText String Format SELECT FROM 0 WHERE ROWNUM lt maxRecords command CommandT
  • 在 LINQ 查询中返回不带时间的日期

    我正在编写一个查询 我想计算按日期联系我们的呼叫中心的次数 看起来很简单 但由于联系日期字段是日期时间字段 我得到了时间 因此当我按联系日期 时间 分组时 每个联系日期实例的计数为 1 所以 我想只按日期分组 而不按时间分组 下面是我用来查
  • C++ 求二维数组每一行的最大值

    我已经设法用这个找到我的二维数组的每一行的最小值 void findLowest int A Cm int n int m int min A 0 0 for int i 0 i lt n i for int j 0 j lt m j if
  • 如何在C++中实现模板类协变?

    是否可以以这样一种方式实现类模板 如果模板参数相关 一个对象可以转换为另一个对象 这是一个展示这个想法的例子 当然它不会编译 struct Base struct Derived Base template
  • fgets() 和 Ctrl+D,三次才能结束?

    I don t understand why I need press Ctrl D for three times to send the EOF In addition if I press Enter then it only too
  • 使用 C# 在 WinRT 中获取可用磁盘空间

    DllImport kernel32 dll SetLastError true static extern bool GetDiskFreeSpaceEx string lpDirectoryName out ulong lpFreeBy
  • HttpClient 像浏览器一样请求

    当我通过 HttpClient 类调用网站 www livescore com 时 我总是收到错误 500 可能服务器阻止了来自 HttpClient 的请求 1 还有其他方法可以从网页获取html吗 2 如何设置标题来获取html内容 当
  • 在 ASP.Net Core 2.0 中导出到 Excel

    我曾经使用下面的代码在 ASP NET MVC 中将数据导出到 Excel Response AppendHeader content disposition attachment filename ExportedHtml xls Res
  • A* 之间的差异 pA = 新 A;和 A* pA = 新 A();

    在 C 中 以下两个动态对象创建之间的确切区别是什么 A pA new A A pA new A 我做了一些测试 但似乎在这两种情况下 都调用了默认构造函数 并且仅调用了它 我正在寻找性能方面的任何差异 Thanks If A是 POD 类
  • 像“1$”这样的位置参数如何与 printf() 一起使用?

    By man I find printf d width num and printf 2 1 d width num 是等价的 但在我看来 第二种风格应该与以下相同 printf d num width 然而通过测试似乎man是对的 为什
  • 网络参考共享类

    我用 Java 编写了一些 SOAP Web 服务 在 JBoss 5 1 上运行 其中两个共享一个类 AddressTO Web 服务在我的 ApplycationServer 上正确部署 一切都很顺利 直到我尝试在我的 C 客户端中使用
  • 什么是 C 语言的高效工作流程? - Makefile + bash脚本

    我正在开发我的第一个项目 该项目将跨越多个 C 文件 对于我的前几个练习程序 我只是在中编写了我的代码main c并使用编译gcc main c o main 当我学习时 这对我有用 现在 我正在独自开展一个更大的项目 我想继续自己进行编译
  • 将应用程序从 Microsoft Access 迁移到 VB 或 C#.NET

    我目前正试图说服管理层需要将我们的应用程序之一移植到 NET 该应用程序已经发展成为 Access 中的一个庞然大物 SQL 后端 拥有 700 个链接表 650 个表单 子表单 130 个模块和 850 个查询 我几乎知道这样做的所有主要
  • 作为字符串的动态属性名称

    使用 DocumentDB 创建新文档时 我想设置属性名称动态地 目前我设置SomeProperty 像这样 await client CreateDocumentAsync dbs db colls x new SomeProperty
  • ListDictionary 类是否有通用替代方案?

    我正在查看一些示例代码 其中他们使用了ListDictionary对象来存储少量数据 大约 5 10 个对象左右 但这个数字可能会随着时间的推移而改变 我使用此类的唯一问题是 与我所做的其他所有事情不同 它不是通用的 这意味着 如果我在这里
  • 方法参数内的变量赋值

    我刚刚发现 通过发现错误 你可以这样做 string s 3 int i int TryParse s hello out i returns false 使用赋值的返回值是否合法 Obviously i is but is this th
  • 在 ASP.NET 中将事件冒泡为父级

    我已经说过 ASP NET 中的层次结构 page user control 1 user control 2 control 3 我想要做的是 当控件 3 它可以是任何类型的控件 我一般都想这样做 让用户用它做一些触发回发的事情时 它会向
  • C++ 成员函数中的“if (!this)”有多糟糕?

    如果我遇到旧代码if this return 在应用程序中 这种风险有多严重 它是一个危险的定时炸弹 需要立即在应用程序范围内进行搜索和销毁工作 还是更像是一种可以悄悄留在原处的代码气味 我不打算writing当然 执行此操作的代码 相反
  • 如何将字符串“07:35”(HH:MM) 转换为 TimeSpan

    我想知道是否有办法将 24 小时时间格式的字符串转换为 TimeSpan 现在我有一种 旧时尚风格 string stringTime 07 35 string values stringTime Split TimeSpan ts new
  • 不同类型的指针可以互相分配吗?

    考虑到 T1 p1 T2 p2 我们可以将 p1 分配给 p2 或反之亦然吗 如果是这样 是否可以不使用强制转换来完成 或者我们必须使用强制转换 首先 让我们考虑不进行强制转换的分配 C 2018 6 5 16 1 1 列出了简单赋值的约束

随机推荐

  • 如何将 bean 注入 Spring Condition 类?

    我正在定义条件 稍后我将检查这些条件以动态加载我的服务接口的两个实现之一 Component public class IsPolicyEnabled implements Condition Autowired private MyPro
  • 如果可以构造 HttpContext 为什么要模拟它呢?

    我一直在 ASP NET 中以某种方式伪造 模拟 存根 HttpContext 在 ASP NET MVC MonoRail 中更容易 但我可以看到 HttpContext 本身可以轻松构建 只需几行代码即可 var tw new Stri
  • 我可以通过计算表达式来确定并可能设置为 null 的属性吗?

    我有一个服务 它接受一个对象 并根据其中的属性执行不同的操作 这样 这些属性中的任何一个都可以为 null 这意味着不执行此操作 我正在尝试创建一个非常简单易用的 API 来在某些属性可能深达多个级别的情况下执行此操作 这是当前实现的示例
  • 错误“命名空间不直接包含字段或方法等成员”

    我正在尝试构建我的 C 项目 但收到错误消息 命名空间不直接包含字段或方法等成员 它标记了 app config 文件的第一个字符 小于号 我检查了所有文件 查找命名空间内直接存在变量或函数的位置 但什么也没发现 app config 看起
  • 如何在 Django 中用 None 保存 FileField?

    我有带有 Avatar 字段的模型配置文件 使用 FileField class Profile models Model avatar models FileField Uploaded avatar of profile storage
  • 查找文件中包含重复字符的行

    我需要一些帮助来查找文本文件中包含重复字符的行 我更喜欢使用 bash 但任何其他方法都可以 一个小例子只是为了让事情变得清楚 文件 txt 1234 11234 abcd 12234 ab321 1233 zs11w 12w2 所需的输出
  • 这两种算法的结果有区别吗?

    这两种算法用于检查有效的会员号码 第一个是公司给我的 第二个是我设计的 从我的测试中我看不出它们在功能上有任何区别 有没有任何情况下任何人都可以看到他们会返回不同的输出 test input 6014355021355010 or 6014
  • 使用适用于 Amazon S3 存储桶的 Java SDK 下载大量文件

    我有大量文件需要从 S3 存储桶下载 我的问题类似于本文 https stackoverflow com questions 1051275 downloading a large number of files from s3除非我想用
  • UIWebView背景颜色

    我正在将 HTML 字符串加载到 UIWebView 中 以便能够查看富文本 到目前为止 一切都很好 但我有一个小问题 在我的 Nib 文件中 我将背景属性设置为绿色 然而 当它显示时 背景是白色的 然后 在类文件中 我添加了以下内容 my
  • Django 外键查询最佳实践

    模型 py class Category models Model name models CharField max length 50 class SubCatergory models Model parent category mo
  • Plotly:并排图之间的 shareX

    我想要两个并排的图共享相同的 X 轴和相同的工具栏 这意味着 通过放大第一个图 第二个图应自动调整大小到相同的缩放区域 一种方法是将图堆叠在另一个之上 使用shareX TRUE 但我需要他们并排 在 python 中似乎有一种方法可以做到
  • 便宜又令人愉快的 rand() 替换

    在对大型游戏程序进行分析后 我发现库函数 rand 消耗了总处理时间的相当一部分 我对随机数生成器的要求不是很繁重 它是否通过大量纯随机性统计测试并不重要 我只是想要一些便宜又令人愉快而且速度非常快的东西 有什么建议么 很少有常用的算法比L
  • 如何使用 useContext 更改 Context 的值?

    使用useContextReact 16 8 的 hook 效果很好 您可以创建组件 使用挂钩并利用上下文值 不会出现任何问题 我不确定如何将更改应用于上下文提供程序值 1 useContext 钩子严格来说是消费上下文值的一种手段吗 2
  • 从 Windows 服务通过调制解调器播放语音

    我正在开发一个 VB NET Windows 服务 该服务持续检查 BMS 数据库是否有新警报 并拨打电话远程警告操作员 我目前正在使用 NET TAPI 包装器和 SAPI 5 3 互操作程序集 我通过电话交谈的步骤是 初始化TAPI接口
  • 如何从主机到 mysql docker 容器执行 mysqldump 命令

    我想为在 docker 容器中运行的数据库创建 mysql 转储 但是 我不想进入容器并执行命令 而是从主机执行此操作 有没有办法做到 我尝试了一些东西 但可能我的命令是错误的 docker exec d mysql sh mysqldum
  • 如何修复 checkmarx 信任边界违规

    我保留用户输入请求中的值 查克马克思抱怨有违反信任边界 从元素请求获取用户输入 该元素的值在没有经过适当清理或验证的情况下流经代码 并最终存储在服务器端 Session 对象中 我还发现这个帖子 https stackoverflow co
  • Java 基本数据类型修饰符是什么?

    好吧 我已经用 Java 编程三年了 现在 我认为自己非常有经验 然而 在查看 Java SE 源代码时 我遇到了一些意想不到的事情 in class Double public static final double MIN NORMAL
  • MPI 中的幽灵细胞交换模式

    我正在使用 MPI 实现分布式图像 灰度 卷积 我现有的模式是在根进程中将图像读取为一维扁平数组 然后将它们分散到所有进程 行分解 然后执行MPI Gather在根进程中 然后再次将图像作为一维展平数组写出 显然 这不会给出预期的结果 因为
  • Arduino 无法被识别

    我不确定这是问问题的正确地方 但我在 stackoverflow 上看到过其他 Arduino 线程 所以我认为没问题 我的 arduino uno 兼容板未被识别 我在 Windows 8 和 Windows XP 上尝试过 当我打开设备
  • 以编程方式设置并保存与导入资源关联的图标

    我有一些自动生成的数据被导出到我的 Unity 项目中 为了帮助我 我想为这些资产分配一个自定义图标以清楚地识别它们 这当然可以通过编辑器本身实现 但理想情况下我希望在导入时自动发生 为此 我编写了一个 AssetPostProcessor