当前位置:网站首页>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://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;
}
}
边栏推荐
- C4D learning notes 2- animation - timeline and time function
- Monthly observation of internet medical field in May 2022
- HW primary flow monitoring, what should we do
- The "go to definition" in VS2010 does not respond or prompts the solution of "symbol not found"
- Whole process analysis of unity3d rendering pipeline
- 2022山东智慧养老展,适老穿戴设备展,养老展,山东老博会
- Annexb and avcc are two methods of data segmentation in decoding
- 喜讯!科蓝SUNDB数据库与鸿数科技隐私数据保护管理软件完成兼容性适配
- 2022第四届中国(济南)国际智慧养老产业展览会,山东老博会
- Async and await
猜你喜欢
After UE4 is packaged, mesh has no material problem
Spin animation of Cocos performance optimization
Webgl texture
Use of SVN
Apache Doris刚“毕业”:为什么应关注这种SQL数据仓库?
LeetCode2_ Add two numbers
Three. JS introductory learning notes 08:orbitcontrols JS plug-in - mouse control model rotation, zoom in, zoom out, translation, etc
The rebound problem of using Scrollview in cocos Creator
20th anniversary of agile: a failed uprising
尤雨溪,来了!
随机推荐
招标公告:盘锦市人民医院盘锦医院数据库维保项目
Virtual memory, physical memory /ram what
Nacos conformance protocol cp/ap/jraft/distro protocol
AE learning 02: timeline
Syntaxhighlight highlights the right scroll bar
[quick start of Digital IC Verification] 25. AHB sramc of SystemVerilog project practice (5) (AHB key review, key points refining)
Simple understanding and application of TS generics
How to deploy the super signature distribution platform system?
Android -- jetpack: the difference between livedata setValue and postvalue
Async and await
Detailed explanation of unity hot update knowledge points and introduction to common solution principles
[wechat applet] Chapter (5): basic API interface of wechat applet
有钱人买房就是不一样
Three. JS introductory learning notes 11:three JS group composite object
[markdown grammar advanced] make your blog more exciting (IV: set font style and color comparison table)
航天宏图信息中标乌鲁木齐某单位数据库系统研发项目
OpenGL's distinction and understanding of VAO, VBO and EBO
神经网络c语言中的指针是怎么回事
numpy---基础学习笔记
持续创作,还得靠它!