首页 文章

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

提问于
浏览
8

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

为此,我编写了一个AssetPostProcessor,它应该为我解决这个问题 . 在下面的示例中(适用于MonoScripts作为示例,但可以应用于任何类型的资产),所有新导入的脚本都将分配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(); 呼叫 .

然而,看着之间手动分配图标(工作)和编程做的差别,不存在与该资产相关联的元文件的 icon 字段,并获得手动分配图标时确定,但不是在我的脚本的情况 . (在脚本情况下,元文件甚至没有更新)

什么给出了什么?当(显然)只有我正在改变的元数据时,我是否必须做任何特别的事情?我有什么简单的俯视吗?

2 回答

  • 5

    用这段代码进行实验并得出结论,这是一个bug . 与Unity联系,这是他们的回复:

    目前,它是一个提交的错误,我们的开发人员团队正在调查它 . 似乎这个错误似乎是因为AssetDatabes.SaveAssets()没有保存更改 .

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

    Processing and Saving Data when OnPostprocessAllAssets is called:

    1 . 创建一个Json文件设置,如果它不存在,将保存这些设置 .

    2 . 调用 OnPostprocessAllAssets 时,加载旧的Json文件设置 .

    4 . 在资产上添加花哨的图标 .

    5 . 遍历加载的Json文件设置并检查它是否包含 importedAssets 参数中的文件 .

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

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

    Auto re-apply the fancy icon when Unity loads:

    1 . 为 IconAssignmentPostProcessor 类添加一个静态构造函数 . 当加载Editor时以及调用 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时,这应该包含花哨的图标 .

  • 0

相关问题