当前位置:网站首页>Unity drawing plug-in = = [support the update of the original atlas]

Unity drawing plug-in = = [support the update of the original atlas]

2022-07-07 15:53:00 Le_ Sam

Preface :

Project needs ,1. It needs to be provided to the art collection tool ,2. Atlas update function , So that the subgraphs in the new atlas do not have to be dragged and positioned again

Solutions :

1.unity Call external TexturePacker The command line tool executes the composite ,unity according to TP The generated data cuts out multiple pieces of the atlas sprite

2. When dragging and positioning subgraphs in the atlas , Corresponding GUID And FileID. Therefore, the new atlas updates the corresponding GUID And FileID that will do , however API No corresponding interface found , So start with the resource itself txt Mode on , Force the replacement of the corresponding ID

Reference documents :

https://blog.csdn.net/pdw_jsp/article/details/83623150?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159900871219725264608797%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=159900871219725264608797&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v2~rank_blog_v1-4-83623150.pc_v2_rank_blog_v1&utm_term=TexturePacker+%E4%B8%80%E9%94%AE%E6%89%93%E5%8C%85&spm=1018.2118.3001.4187
 

https://www.xuanyusong.com/archives/4207

 

effect :

 

 

 

Source code :

The following three files , Placed in the project Assets\Editor that will do

using System;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using UnityEditor;
using System.Text;
using System.Diagnostics;
using System.Linq;
using System.Xml;
using System.Collections;
using LuaFramework;

public class TexturePackerBuild : Editor
{
    private const string BuildDir = "Assets/TexturePacker/ Package the atlas ";

    /// <summary>
    /// TexturePacker.exe ###https://www.codeandweb.com/texturepacker/documentation/texture-settings
    /// </summary>
    private const string Paramet = " --sheet {0}.png --data {1}.xml --format sparrow --trim-mode CropKeepPos --pack-mode Best --algorithm MaxRects --max-size 4096 --size-constraints POT --disable-rotation {2}";
    /// <summary>
    ///  The output directory 
    /// </summary>
    private const string OutPutDirRoot = "Assets/TPSpriteBuild/";

    private static string tpDir = "";
    private static string argument = "";

    [MenuItem(BuildDir, false)]
    public static void BuildOneTP()
    {

        if (Directory.Exists(OutPutDirRoot) == false)
        {
            Directory.CreateDirectory(OutPutDirRoot);
        }

        var assetPaths = Selection.assetGUIDs.Select(AssetDatabase.GUIDToAssetPath).ToList();

        List<string> filePathList = new List<string>();
        foreach (var assetPath in assetPaths)
        {
            if (AssetDatabase.IsValidFolder(assetPath))
            {
                string[] filesPath = Directory.GetFiles(assetPath);
                foreach (var filePath in filesPath)
                {
                    if (filePathList.Contains(filePath) == false)
                    {
                        filePathList.Add(filePath);
                    }
                    else
                    {
                        UnityEngine.Debug.LogErrorFormat(" Same file detected  {0}", assetPath);
                    }
                }
            }
            else
            {
                filePathList.Add(assetPath);
            }
        }

        Dictionary<string, FileData> fileDic = new Dictionary<string, FileData>();
        foreach (var path in filePathList)
        {
            var dir = Path.GetFileName(Path.GetDirectoryName(path));
            var fileName = Path.GetFileName(path);
            UnityEngine.Debug.LogFormat("_TP dirName {0} _TP fileName {1} _TP fullPath {2}", dir, fileName, path);

            if (fileDic.ContainsKey(dir) == false)
            {
                FileData fileData = new FileData();
                fileData.filesList = new List<string>();
                fileDic[dir] = fileData;
                fileDic[dir].dirName = dir;
            }

            fileDic[dir].filesList.Add(path);
        }

        foreach (var data in fileDic)
        {
            TexturePackerBuild tpBuild = new TexturePackerBuild();
            tpBuild.Build(data.Value);
        }
    }

    public void Build(FileData data)
    {
        StringBuilder sb = new StringBuilder("");
        GetImageName(data.filesList, ref sb);

        string sheetName = OutPutDirRoot + data.dirName;
        argument = string.Format(Paramet, sheetName, sheetName, sb.ToString());

        tpDir = PlayerPrefs.GetString("_TPInstallDir", "");

        RunExternalApp(tpDir, argument);
    }

    private StringBuilder GetImageName(List<string> fileName, ref StringBuilder sb)
    {
        foreach (var file in fileName)
        {
            string extenstion = Path.GetExtension(file);
            if (extenstion == ".png")
            {
                sb.Append(file);
                sb.Append("  ");
            }
        }
        
        return sb;
    }


    private void RunExternalApp(string command, string argument)
    {
        UnityEngine.Debug.Log("TPSprite Recover");

        ClearOtherFiles();

        ProcessStartInfo start = new ProcessStartInfo(command);
        start.Arguments = argument;
        start.CreateNoWindow = false;
        start.ErrorDialog = true;
        start.UseShellExecute = false;
        start.RedirectStandardOutput = true;
        start.RedirectStandardError = true;
        start.RedirectStandardInput = true;
        start.StandardOutputEncoding = System.Text.UTF8Encoding.UTF8;
        start.StandardErrorEncoding = System.Text.UTF8Encoding.UTF8;

        try
        {
            Process p = Process.Start(start);
            p.WaitForExit();
            p.Close();
            AssetDatabase.Refresh();

            bool isNullFile; //  Judge whether the file in the output directory is empty 
            string outPngPath;
            BuildTexturePacker(out isNullFile,out outPngPath);
            if (isNullFile == false)
            {
                tpDir = command;
                PlayerPrefs.SetString("_TPInstallDir", command);
                SelectAtlasUpdataWindow(outPngPath);
            }
            else
            {
                //  The output file is empty , guess exe Incorrect use , Re import exe
                OnError(" No pictures were detected in the output directory , Please re import ");
            }
        }
        catch (Exception ex)
        {
            OnError(ex.Message);
        }
    }

    /// <summary>
    ///  Clean up the original image under the output directory 
    /// </summary>
    private void ClearOtherFiles()
    {
        string[] fileName = Directory.GetFiles(OutPutDirRoot);
        if (fileName != null && fileName.Length > 0)
        {
            for (int i = 0; i < fileName.Length; i++)
            {
                string extenstion = Path.GetExtension(fileName[i]);
                if (extenstion == ".png" || extenstion == ".xml")
                {
                    File.Delete(fileName[i]);
                }
            }
        }

    }

    /// <summary>
    ///  establish Texture
    /// </summary>
    /// <param name="isNull"></param>
    /// <param name="outPngPath"></param>
    public void BuildTexturePacker(out bool isNull, out string outPngPath)
    {
        isNull = true; 
        outPngPath = "";
        string[] imagePath = Directory.GetFiles(OutPutDirRoot);
        foreach (string path in imagePath)
        {
            if (Path.GetExtension(path) == ".png" || Path.GetExtension(path) == ".PNG")
            {
                Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
                string rootPath = OutPutDirRoot + texture.name;
                string pngPath = rootPath + "/" + texture.name + "_" + DateTime.Now.ToString("hh_mm_ss") + ".png";

                outPngPath = pngPath;
                isNull = false;

                if (Directory.Exists(rootPath) == false)
                {
                    Directory.CreateDirectory(rootPath);
                }
                File.Copy(OutPutDirRoot + texture.name + ".png", pngPath);

                AssetDatabase.Refresh();

                FileStream fs = new FileStream(OutPutDirRoot + texture.name + ".xml", FileMode.Open);
                StreamReader sr = new StreamReader(fs);
                string jText = sr.ReadToEnd();
                fs.Close();
                sr.Close();

                WriteMeta(jText, pngPath);
            }
        }

        ClearOtherFiles();
        AssetDatabase.Refresh();
    }

    void SelectAtlasUpdataWindow(string pngPath)
    {
        TPSelectFileWindow win = new TPSelectFileWindow();
        win.Popup(pngPath, UpdataAssetRes);
    }

    void UpdataAssetRes(string opPath, Texture pendingTex)
    {
        var srcObj = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(opPath);
        TPFindReplaceRes tpFindRep = new TPFindReplaceRes();
        tpFindRep.OnTPReplaceAssetData(pendingTex, srcObj);
    }

    // Write a message to SpritesSheet in 
    void WriteMeta(string jText, string path)
    {
        UnityEngine.Debug.Log("WriteMeta " + path);

        XmlDocument xml = new XmlDocument();
        xml.LoadXml(jText);
        XmlNodeList elemList = xml.GetElementsByTagName("SubTexture");

        Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
        string impPath = AssetDatabase.GetAssetPath(texture);

        TextureImporter asetImp = TextureImporter.GetAtPath(impPath) as TextureImporter;
        SpriteMetaData[] metaData = new SpriteMetaData[elemList.Count];

        for (int i = 0, size = elemList.Count; i < size; i++)
        {
            XmlElement node = (XmlElement)elemList.Item(i);

            Rect rect = new Rect();
            rect.x = int.Parse(node.GetAttribute("x"));
            rect.y = texture.height - int.Parse(node.GetAttribute("y")) - int.Parse(node.GetAttribute("height"));
            rect.width = int.Parse(node.GetAttribute("width"));
            rect.height = int.Parse(node.GetAttribute("height"));

            metaData[i].rect = rect;
            metaData[i].pivot = new Vector2(0.5f, 0.5f);
            metaData[i].name = node.GetAttribute("name");
        }

        asetImp.spritesheet = metaData;
        asetImp.textureType = TextureImporterType.Sprite;
        asetImp.spriteImportMode = SpriteImportMode.Multiple;
        asetImp.mipmapEnabled = false;
        asetImp.SaveAndReimport();
    }

    private string OpenTPEXE()
    {
        string path = EditorUtility.OpenFilePanel(" Please locate TexturePacker.exe Program , For subsequent operations ", "", "exe");
        return path;
    }

    private void OnError(string err)
    {
        UnityEngine.Debug.LogError("TPBuild Err:" + err);
        EditorUtility.DisplayDialog(" Please reposition TexturePacker.exe Program !", "Err:" + err, " determine ");
        var path = OpenTPEXE();
        if (path.Length != 0)
        {
            RunExternalApp(path, argument);
        }
    }

    public class FileData
    {
        public string dirName;
        public List<string> filesList;
    }
}

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

/// <summary>
///  Editor main interface 
/// </summary>
public class TPSelectFileWindow : EditorWindow {

    private Action<string, Texture> _callBack;
    private string _opPath;
    private Texture _selectTex;

    public void Popup(string opPath, Action<string, Texture> cb)
    {
        _callBack = cb;
        _opPath = opPath;

        var isSeek = EditorUtility.DisplayDialog(" Waiting for execution ...", " Whether to update the original atlas ,  Currently, only a single atlas can be updated ", " determine ", " Cancel ");
        if (isSeek == true)
        {
            TPSelectFileWindow window = EditorWindow.GetWindow(typeof(TPSelectFileWindow), true, " Waiting for execution ...") as TPSelectFileWindow;
            window.minSize = new Vector2(450, 300);
            window.Show();
        }
        else
        {
            if (_callBack != null)
            {
                _callBack.Invoke(_opPath, _selectTex);
            }
            _callBack = null;
        }
    }

    private void OnGUI()
    {
        ShowEditorGUI();
    }

    private void ShowEditorGUI()
    {
        _selectTex = EditorGUILayout.ObjectField(" Add the original bound Texture", _selectTex, typeof(Texture), true) as Texture;
        if (_selectTex != null && string.IsNullOrEmpty(_selectTex.name) == false)
        {
             EditorGUILayout.TextField(AssetDatabase.GetAssetOrScenePath(_selectTex));
        }
        
        if (GUILayout.Button(" Close the window and continue "))
        {
            // close window 
            this.Close();
        }
    }


    private void OnDestroy()
    {    
        if (_callBack != null)
        {
            _callBack.Invoke(_opPath, _selectTex);
        }
        _callBack = null;
        _selectTex = null;
    }
}
using UnityEngine;
using UnityEngine.UI;
using UnityEditor;
using System.Collections;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;

public class TPFindReplaceRes {

    Dictionary<string, AssetData> assetDic;
    string srcGUID;
    string tarGUID;

    /// <summary>
    ///  to update Asset data 
    /// </summary>
    /// <param name="srcObj"> Retrieve the located OBJ, It can be discarded after operation </param>
    /// <param name="tarObj"> Wait for the updated data to be clean OBJ</param>
    public void OnTPReplaceAssetData(Object srcObj, Object tarObj) {
        AssetDatabase.Refresh();

        EditorSettings.serializationMode = SerializationMode.ForceText;

        string srcPath = AssetDatabase.GetAssetPath(srcObj);
        string tarPath = AssetDatabase.GetAssetPath(tarObj);

        if (string.IsNullOrEmpty(tarPath) || string.IsNullOrEmpty(srcPath))
        {
            Debug.Log("srcObj = null || tarObj = null");
            return;
        }

        Debug.LogFormat("srcPath:{0} , tarPath:{1}", srcPath, tarPath);

        srcGUID = AssetDatabase.AssetPathToGUID(srcPath);
        tarGUID = AssetDatabase.AssetPathToGUID(tarPath);

        OnCreateMetaData(srcPath, tarPath);

        var withoutExtensions = new List<string>() { ".prefab", ".unity", ".mat", ".asset" };
        string[] files = Directory.GetFiles(Application.dataPath, "*.*", SearchOption.AllDirectories).Where(s => withoutExtensions.Contains(Path.GetExtension(s).ToLower())).ToArray();

        int startIndex = 0;
        EditorApplication.update = delegate () {
            string file = files[startIndex];

            bool isCancel = EditorUtility.DisplayCancelableProgressBar(" Matching resources ", file, (float)startIndex / (float)files.Length);

            if (Regex.IsMatch(File.ReadAllText(file), srcGUID))
            {
                OnUpdateData(file);
                var obj = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(GetRelativeAssetsPath(file));
                Debug.Log(" Replacement object  " + file, obj);
            }

            startIndex++;
            if (isCancel || startIndex >= files.Length)
            {
                EditorUtility.ClearProgressBar();
                EditorApplication.update = null;
                startIndex = 0;
                Debug.Log(" End of data update ");
            }
        };
    }

    void OnCreateMetaData(string srcPath, string tarPath)
    {
        string srcMeta = AssetDatabase.GetTextMetaFilePathFromAssetPath(srcPath);
        string tarMeta = AssetDatabase.GetTextMetaFilePathFromAssetPath(tarPath);

        string[] srcFile = File.ReadAllLines(srcMeta);
        string[] tarFile = File.ReadAllLines(tarMeta);

        List<string> smList = new List<string>();
        List<string> tempList = new List<string>();
        
        TextureImporter srcImp = TextureImporter.GetAtPath(srcPath) as TextureImporter;
        TextureImporter tarImp = TextureImporter.GetAtPath(tarPath) as TextureImporter;

        foreach (var spMD in tarImp.spritesheet)
        {
            tempList.Add(spMD.name);
        }

        foreach (var spMD in srcImp.spritesheet)
        {
            if (tempList.Contains(spMD.name))
            {
                smList.Add(spMD.name);
                //Debug.Log(" matching SpriteSheetMeta " + spMeta.name);
            }
        }

        assetDic = new Dictionary<string, AssetData>();
        foreach (var key in smList)
        {
            AssetData data = new AssetData();
            data.name = key;
            assetDic.Add(key, data);

            foreach (var srcStr in srcFile)
            {
                if (srcStr.IndexOf(key) >= 0)
                {
                    var str = srcStr.Trim();
                    var spMetaId = str.Substring(0, str.IndexOf(":"));
                    //Debug.LogFormat("src ==> {0} {1}", key, spMetaId);

                    if (string.IsNullOrEmpty(assetDic[key].src))
                    {
                        assetDic[key].src = spMetaId;
                    }
                }
            }

            foreach (var tarStr in tarFile)
            {
                if (tarStr.IndexOf(key) >= 0)
                {
                    var str = tarStr.Trim();
                    var spMetaId = str.Substring(0, str.IndexOf(":"));
                    //Debug.LogFormat("tar ==> {0} {1}", key, spMetaId);

                    if (string.IsNullOrEmpty(assetDic[key].tar))
                    {
                        assetDic[key].tar = spMetaId;
                    }
                }
            }

            if (string.IsNullOrEmpty(assetDic[key].src) || string.IsNullOrEmpty(assetDic[key].tar))
            {
                assetDic.Remove(key);
            }
        }

        //foreach (var meta in assetDic)
        //{
        //    var data = meta.Value;
        //    Debug.LogFormat("meta ==> name:{0} src:{1} tar:{2}", data.name, data.src, data.tar);
        //}
    }

    void OnUpdateData(string file)
    {

        var allInfo = File.ReadAllLines(file);

        for (int i = 0; i < allInfo.Length; i++)
        {
            var str = allInfo[i];
            if (str.IndexOf(srcGUID) >= 0)
            {
                if (str.IndexOf("guid") >= 0)
                {
                    //  Replace old GUID
                    str = str.Replace(srcGUID, tarGUID);

                    //  Replace old fileID
                    if (str.IndexOf("fileID") >= 0)
                    {
                        foreach (var meta in assetDic)
                        {
                            if (str.IndexOf(meta.Value.src) >= 0)
                            {
                                str = str.Replace(meta.Value.src, meta.Value.tar);
                            }
                        }
                    }
                }

                allInfo[i] = str;
            }
        }

        File.WriteAllLines(file, allInfo);
    }

    static string GetRelativeAssetsPath(string path) {
        return "Assets" + Path.GetFullPath(path).Replace(Path.GetFullPath(Application.dataPath), "").Replace('\\', '/');
    }

    public class AssetData
    {
        public string name;
        public string src;
        public string tar;
    }
}



 

原网站

版权声明
本文为[Le_ Sam]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202130609270659.html