From 8061a124f321708ea8fbc8cbff58db0df0128e0c Mon Sep 17 00:00:00 2001 From: ALEXTANG <574809918@qq.com> Date: Thu, 13 Apr 2023 16:11:15 +0800 Subject: [PATCH] Create SpritePostprocessor.cs --- .../GameScripts/Editor/SpritePostprocessor.cs | 489 ++++++++++++++++++ 1 file changed, 489 insertions(+) create mode 100644 Assets/GameScripts/Editor/SpritePostprocessor.cs diff --git a/Assets/GameScripts/Editor/SpritePostprocessor.cs b/Assets/GameScripts/Editor/SpritePostprocessor.cs new file mode 100644 index 00000000..189254f5 --- /dev/null +++ b/Assets/GameScripts/Editor/SpritePostprocessor.cs @@ -0,0 +1,489 @@ +using System; +using System.Collections.Generic; +using System.IO; +using UnityEditor; +using UnityEditor.U2D; +using UnityEngine; +using UnityEngine.U2D; +using Object = UnityEngine.Object; + +/// +/// 图集导入管线。 +/// +public class SpritePostprocessor : AssetPostprocessor +{ + static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) + { + foreach (var s in importedAssets) + { + EditorSpriteSaveInfo.OnImportSprite(s); + } + + foreach (var s in deletedAssets) + { + EditorSpriteSaveInfo.OnDeleteSprite(s); + } + + foreach (var s in movedFromAssetPaths) + { + EditorSpriteSaveInfo.OnDeleteSprite(s); + } + + foreach (var s in movedAssets) + { + EditorSpriteSaveInfo.OnImportSprite(s); + } + } +} + +public static class EditorSpriteSaveInfo +{ + private const string NormalAtlasDir = "Assets/Atlas"; + private const string UISpritePath = "Assets/AssetRaw/UIRaw"; + private const string UIAtlasPath = "Assets/AssetRaw/UIRaw/Atlas"; + private const string UIRawPath = "Assets/AssetRaw/UIRaw/UIRaw"; + private static List m_dirtyAtlasList = new List(); + private static Dictionary> m_allASprites = new Dictionary>(); + private static Dictionary m_uiAtlasMap = new Dictionary(); + private static bool m_inited = false; + private static bool m_dirty = false; + + public static void Init() + { + if (m_inited) + { + return; + } + + EditorApplication.update += CheckDirty; + } + + public static void CheckDirty() + { + if (m_dirty) + { + m_dirty = false; + + AssetDatabase.Refresh(); + float lastProgress = -1; + for (int i = 0; i < m_dirtyAtlasList.Count; i++) + { + string atlasName = m_dirtyAtlasList[i]; + Debug.Log("更新图集 : " + atlasName); + var curProgress = (float)i / m_dirtyAtlasList.Count; + if (curProgress > lastProgress + 0.01f) + { + lastProgress = curProgress; + var progressText = $"当前进度:{i}/{m_dirtyAtlasList.Count} {atlasName}"; + bool cancel = EditorUtility.DisplayCancelableProgressBar("刷新图集" + atlasName, progressText, curProgress); + if (cancel) + { + break; + } + } + + bool isUI = atlasName.StartsWith("UIRaw"); + SaveAtlas(atlasName, isUI); + } + + EditorUtility.ClearProgressBar(); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + m_dirtyAtlasList.Clear(); + } + } + + public static void OnImportSprite(string assetPath) + { + if (!assetPath.StartsWith(UISpritePath)) + { + return; + } + + TextureImporter ti = AssetImporter.GetAtPath(assetPath) as TextureImporter; + + if (ti != null) + { + var modify = false; + + if (assetPath.StartsWith(UISpritePath)) + { + if (ti.textureType != TextureImporterType.Sprite) + { + ti.textureType = TextureImporterType.Sprite; + modify = true; + } + + if (!string.IsNullOrEmpty(ti.spritePackingTag)) + { + ti.spritePackingTag = string.Empty; + modify = true; + } + + var setting = new TextureImporterSettings(); + ti.ReadTextureSettings(setting); + if (setting.spriteGenerateFallbackPhysicsShape) + { + setting.spriteGenerateFallbackPhysicsShape = false; + ti.SetTextureSettings(setting); + modify = true; + } + + if (IsKeepRawImage(assetPath)) + { + //调整android格式 + var andPlatformSettings = ti.GetPlatformTextureSettings("Android"); + if (!andPlatformSettings.overridden) + { + andPlatformSettings.overridden = true; + modify = true; + } + + if (andPlatformSettings.format != TextureImporterFormat.ASTC_6x6) + { + andPlatformSettings.format = TextureImporterFormat.ASTC_6x6; + ti.SetPlatformTextureSettings(andPlatformSettings); + modify = true; + } + + //调整ios格式 + var iosPlatformSettings = ti.GetPlatformTextureSettings("iPhone"); + if (!iosPlatformSettings.overridden) + { + iosPlatformSettings.overridden = true; + modify = true; + } + + if (iosPlatformSettings.format != TextureImporterFormat.ASTC_5x5) + { + iosPlatformSettings.format = TextureImporterFormat.ASTC_5x5; + iosPlatformSettings.compressionQuality = 50; + ti.SetPlatformTextureSettings(iosPlatformSettings); + modify = true; + } + } + } + + if (modify) + { + ti.SaveAndReimport(); + } + + if (ti.textureType == TextureImporterType.Sprite) + { + OnProcessSprite(assetPath); + } + } + } + + /// + /// 是否保持散图(不打图集) + /// + /// + /// + public static bool IsKeepRawImage(string dirPath) + { + return dirPath.Contains("UIRaw/Raw/") || dirPath.Contains("UIRaw_Raw_"); + } + + public static string GetSpritePath(string assetPath) + { + string path = assetPath.Substring(0, assetPath.LastIndexOf(".")); + path = path.Replace("Assets/AssetRaw/", ""); + return path; + } + + /// + /// 根据文件路径,返回图集名称 + /// + /// + /// + public static string GetPackageTag(string fullName) + { + fullName = fullName.Replace("\\", "/"); + int idx = fullName.LastIndexOf("UIRaw", StringComparison.Ordinal); + if (idx == -1) + { + return ""; + } + + if (IsKeepRawImage(fullName)) + { + return ""; + } + + var atlasPath = fullName.Substring(idx); + string str = atlasPath; + str = str.Substring(0, str.LastIndexOf("/", StringComparison.Ordinal)).Replace("/", "_"); + + return str; + } + + public static void OnProcessSprite(string assetPath) + { + if (!assetPath.StartsWith("Assets")) + { + return; + } + + if (assetPath.StartsWith("Assets/UIRaw_Delete")) + { + return; + } + + Init(); + + var spriteName = Path.GetFileNameWithoutExtension(assetPath); + var spritePath = GetSpritePath(assetPath); + if (!m_uiAtlasMap.TryGetValue(spriteName, out string oldAssetPath) || spritePath == oldAssetPath) + { + m_uiAtlasMap[spriteName] = spritePath; + m_dirty = true; + } + else + { + Debug.LogError($"有重名的图片:{spriteName}\n旧图集:{oldAssetPath}\n新图集:{spritePath} "); + m_uiAtlasMap[spriteName] = spritePath; + m_dirty = true; + } + + string atlasName = GetPackageTag(assetPath); + if (string.IsNullOrEmpty(atlasName)) + { + bool keepRaw = IsKeepRawImage(assetPath); + if (!keepRaw) + { + Debug.LogError($"empty packingTag of asset :{assetPath} !!!"); + } + + return; + } + else + { + List ret; + if (!m_allASprites.TryGetValue(atlasName, out ret)) + { + ret = new List(); + m_allASprites.Add(atlasName, ret); + } + + if (!ret.Contains(assetPath)) + { + ret.Add(assetPath); + m_dirty = true; + if (!m_dirtyAtlasList.Contains(atlasName)) + { + m_dirtyAtlasList.Add(atlasName); + } + } + } + } + + public static void OnDeleteSprite(string assetPath) + { + if (assetPath.StartsWith("Assets/UIRaw_Delete")) + { + return; + } + + if (!assetPath.StartsWith(UISpritePath)) + { + return; + } + + Init(); + string atlasName = GetPackageTag(assetPath); + if (!m_allASprites.TryGetValue(atlasName, out var ret)) + { + return; + } + + //改成文件名的匹配 + if (!ret.Exists(s => Path.GetFileName(s) == Path.GetFileName(assetPath))) + { + return; + } + + if (assetPath.StartsWith(UISpritePath)) + { + var spriteName = Path.GetFileNameWithoutExtension(assetPath); + if (m_uiAtlasMap.ContainsKey(spriteName)) + { + m_uiAtlasMap.Remove(spriteName); + m_dirty = true; + } + } + + ret.Remove(assetPath); + m_dirty = true; + if (!m_dirtyAtlasList.Contains(atlasName)) + { + m_dirtyAtlasList.Add(atlasName); + } + } + + #region 更新图集 + + public static void SaveAtlas(string atlasName, bool isUI) + { + List spriteList = new List(); + if (m_allASprites.ContainsKey(atlasName)) + { + var list = m_allASprites[atlasName]; + list.Sort(StringComparer.Ordinal); + + foreach (var s in list) + { + var sprite = AssetDatabase.LoadAssetAtPath(s); + if (sprite != null) + { + spriteList.Add(sprite); + } + } + } + + var path = $"{NormalAtlasDir}/{atlasName}.spriteatlas"; + + if (spriteList.Count == 0) + { + if (File.Exists(path)) + { + AssetDatabase.DeleteAsset(path); + } + + return; + } + + var atlas = new SpriteAtlas(); + var setting = new SpriteAtlasPackingSettings + { + blockOffset = 1, + padding = 2, + enableRotation = true + }; + + bool isOpaque = atlasName.Contains("Opaque"); + + var textureSetting = new SpriteAtlasTextureSettings + { + generateMipMaps = false, + sRGB = true, + filterMode = FilterMode.Bilinear + }; + atlas.SetTextureSettings(textureSetting); + + var iphonePlatformSetting = atlas.GetPlatformSettings("iPhone"); + if (!iphonePlatformSetting.overridden) + { + iphonePlatformSetting.overridden = true; + iphonePlatformSetting.format = isOpaque ? TextureImporterFormat.ASTC_5x5 : TextureImporterFormat.ASTC_5x5; + iphonePlatformSetting.compressionQuality = 100; + atlas.SetPlatformSettings(iphonePlatformSetting); + } + + var androidPlatformSetting = atlas.GetPlatformSettings("Android"); + if (isOpaque && !androidPlatformSetting.overridden) + { + androidPlatformSetting.overridden = true; + androidPlatformSetting.format = TextureImporterFormat.ETC_RGB4; + androidPlatformSetting.compressionQuality = 100; + atlas.SetPlatformSettings(androidPlatformSetting); + } + + atlas.SetPackingSettings(setting); + atlas.Add(spriteList.ToArray()); + + AssetDatabase.CreateAsset(atlas, path); + } + + #endregion + + #region 重新生成图集 + + private static Dictionary> m_tempAllASprites = new Dictionary>(); + + [MenuItem("TEngine/图集/重新生成UI图集")] + static void ForceGenAtlas() + { + Init(); + List needSaveAtlas = new List(); + m_tempAllASprites.Clear(); + var findAssets = AssetDatabase.FindAssets("t:sprite", new[] { UIAtlasPath }); + foreach (var findAsset in findAssets) + { + var path = AssetDatabase.GUIDToAssetPath(findAsset); + var atlasName = GetPackageTag(path); + if (!m_tempAllASprites.TryGetValue(atlasName, out var spriteList)) + { + spriteList = new List(); + m_tempAllASprites[atlasName] = spriteList; + } + + if (!spriteList.Contains(path)) + { + spriteList.Add(path); + } + } + + //有变化的才刷 + var iter = m_tempAllASprites.GetEnumerator(); + while (iter.MoveNext()) + { + bool needSave = false; + var atlasName = iter.Current.Key; + var newSpritesList = iter.Current.Value; + + List existSprites; + if (m_allASprites.TryGetValue(atlasName, out existSprites)) + { + if (existSprites.Count != newSpritesList.Count) + { + needSave = true; + existSprites.Clear(); + existSprites.AddRange(newSpritesList); + } + else + { + for (int i = 0; i < newSpritesList.Count; i++) + { + if (!existSprites.Contains(newSpritesList[i])) + { + needSave = true; + break; + } + } + + if (needSave) + { + existSprites.Clear(); + existSprites.AddRange(newSpritesList); + } + } + } + else + { + needSave = true; + m_allASprites.Add(atlasName, new List(newSpritesList)); + } + + if (needSave && !needSaveAtlas.Contains(atlasName)) + { + needSaveAtlas.Add(atlasName); + } + } + iter.Dispose(); + foreach (var atlas in needSaveAtlas) + { + Debug.LogFormat("Gen atlas:{0}", atlas); + SaveAtlas(atlas, true); + } + + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + + SpriteAtlasUtility.PackAllAtlases(EditorUserBuildSettings.activeBuildTarget); + Debug.Log("Gen end"); + } + + #endregion +} \ No newline at end of file