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

时间:2016-12-02 13:30:06

标签: c# unity3d

我将一些自动生成的数据导出到我的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 个答案:

答案 0 :(得分:5)

使用此代码进行实验并得出结论,这是一个错误。与Unity联系,这是他们的答复:

  

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

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

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

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

2 。调用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时,这应该包含花哨的图标。

答案 1 :(得分:0)