diff --git a/UnityProject/Assets/AssetArt/Atlas.meta b/UnityProject/Assets/AssetArt/Atlas.meta index c36d2097..cab71d8f 100644 --- a/UnityProject/Assets/AssetArt/Atlas.meta +++ b/UnityProject/Assets/AssetArt/Atlas.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 6b4dd55e1b47da54697b93c6bc2bd337 +guid: 9d6134158c52933418338d95eebd1c39 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/UnityProject/Assets/AssetArt/Atlas/Atlas_Battle.spriteatlasv2 b/UnityProject/Assets/AssetArt/Atlas/Atlas_Battle.spriteatlasv2 new file mode 100644 index 00000000..0471a446 --- /dev/null +++ b/UnityProject/Assets/AssetArt/Atlas/Atlas_Battle.spriteatlasv2 @@ -0,0 +1,20 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!612988286 &1 +SpriteAtlasAsset: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + serializedVersion: 2 + m_MasterAtlas: {fileID: 0} + m_ImporterData: + packables: + - {fileID: 21300000, guid: c95935206d18f42399e9881ce6bdf61c, type: 3} + - {fileID: 21300000, guid: 1f44cb90b6ae648c783dac573bfe9cd0, type: 3} + - {fileID: 21300000, guid: bfad0e64f8ef1491c8def7e679187b89, type: 3} + - {fileID: 21300000, guid: a43cb397a444ce44f9becc183ced96ed, type: 3} + - {fileID: 21300000, guid: f43899c31dd434901b0422f98bcde88b, type: 3} + - {fileID: 21300000, guid: 01ccaea9b49214edda39f03f648b5b8b, type: 3} + m_IsVariant: 0 diff --git a/UnityProject/Assets/AssetArt/Atlas/Atlas_Battle.spriteatlasv2.meta b/UnityProject/Assets/AssetArt/Atlas/Atlas_Battle.spriteatlasv2.meta new file mode 100644 index 00000000..b381ba67 --- /dev/null +++ b/UnityProject/Assets/AssetArt/Atlas/Atlas_Battle.spriteatlasv2.meta @@ -0,0 +1,69 @@ +fileFormatVersion: 2 +guid: e6770285dceffae48b253f30f09cd3bc +SpriteAtlasImporter: + externalObjects: {} + textureSettings: + serializedVersion: 2 + anisoLevel: 1 + compressionQuality: 50 + maxTextureSize: 2048 + textureCompression: 0 + filterMode: 1 + generateMipMaps: 0 + readable: 0 + crunchedCompression: 0 + sRGB: 1 + platformSettings: + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: 50 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 1 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: 49 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 1 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: 50 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 1 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + packingSettings: + serializedVersion: 2 + padding: 4 + blockOffset: 1 + allowAlphaSplitting: 0 + enableRotation: 1 + enableTightPacking: 1 + enableAlphaDilation: 1 + secondaryTextureSettings: {} + variantMultiplier: 1 + bindAsDefault: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/AssetArt/Atlas/UIRaw_Atlas_Battle.spriteatlasv2 b/UnityProject/Assets/AssetArt/Atlas/UIRaw_Atlas_Battle.spriteatlasv2 deleted file mode 100644 index b4424a90..00000000 --- a/UnityProject/Assets/AssetArt/Atlas/UIRaw_Atlas_Battle.spriteatlasv2 +++ /dev/null @@ -1,58 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!612988286 &4096168566840163508 -SpriteAtlasAsset: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: UIRaw_Atlas_Battle - m_MasterAtlas: {fileID: 0} - m_ImporterData: - serializedVersion: 2 - textureSettings: - serializedVersion: 2 - anisoLevel: 0 - compressionQuality: 0 - maxTextureSize: 0 - textureCompression: 0 - filterMode: 1 - generateMipMaps: 0 - readable: 0 - crunchedCompression: 0 - sRGB: 1 - platformSettings: - - serializedVersion: 3 - m_BuildTarget: iPhone - m_MaxTextureSize: 2048 - m_ResizeAlgorithm: 0 - m_TextureFormat: 50 - m_TextureCompression: 1 - m_CompressionQuality: 100 - m_CrunchedCompression: 0 - m_AllowsAlphaSplitting: 0 - m_Overridden: 1 - m_AndroidETC2FallbackOverride: 0 - m_ForceMaximumCompressionQuality_BC6H_BC7: 0 - packingSettings: - serializedVersion: 2 - padding: 2 - blockOffset: 1 - allowAlphaSplitting: 0 - enableRotation: 1 - enableTightPacking: 0 - enableAlphaDilation: 0 - secondaryTextureSettings: {} - variantMultiplier: 1 - packables: - - {fileID: 21300000, guid: f43899c31dd434901b0422f98bcde88b, type: 3} - - {fileID: 21300000, guid: 01ccaea9b49214edda39f03f648b5b8b, type: 3} - - {fileID: 21300000, guid: 1f44cb90b6ae648c783dac573bfe9cd0, type: 3} - - {fileID: 21300000, guid: bfad0e64f8ef1491c8def7e679187b89, type: 3} - - {fileID: 21300000, guid: af67f6c46933441daaa64d6880890586, type: 3} - - {fileID: 21300000, guid: c95935206d18f42399e9881ce6bdf61c, type: 3} - - {fileID: 21300000, guid: a43cb397a444ce44f9becc183ced96ed, type: 3} - bindAsDefault: 1 - isAtlasV2: 1 - cachedData: {fileID: 0} - m_IsVariant: 0 diff --git a/UnityProject/Assets/AssetArt/Atlas/UIRaw_Atlas_Battle.spriteatlasv2.meta b/UnityProject/Assets/AssetArt/Atlas/UIRaw_Atlas_Battle.spriteatlasv2.meta deleted file mode 100644 index 7d8b5d40..00000000 --- a/UnityProject/Assets/AssetArt/Atlas/UIRaw_Atlas_Battle.spriteatlasv2.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: f8e251863479c4648a2271dcc7504237 -SpriteAtlasImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor.meta b/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor.meta new file mode 100644 index 00000000..f438ca65 --- /dev/null +++ b/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 16fac2fa602633346b6f45f4362f28f7 +timeCreated: 1738748198 \ No newline at end of file diff --git a/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/AtlasConfiguration.cs b/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/AtlasConfiguration.cs new file mode 100644 index 00000000..04466208 --- /dev/null +++ b/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/AtlasConfiguration.cs @@ -0,0 +1,46 @@ +namespace TEngine.Editor +{ +#if UNITY_EDITOR + using UnityEngine; + using UnityEditor; + + [HybridCLR.Editor.Settings.FilePath("ProjectSettings/AtlasConfiguration.asset")] + public class AtlasConfiguration : HybridCLR.Editor.Settings.ScriptableSingleton + { + [Header("目录设置")] + [Tooltip("生成的图集输出目录")] + public string outputAtlasDir = "Assets/AssetArt/Atlas"; + + [Tooltip("需要生成图集的UI根目录")] + public string sourceAtlasRoot = "Assets/AssetRaw/UIRaw/Atlas"; + + [Tooltip("不需要生成图集的UI目录")] + public string excludeFolder = "Assets/AssetRaw/UIRaw/Raw"; + + [Header("平台格式设置")] + public TextureImporterFormat androidFormat = TextureImporterFormat.ASTC_6x6; + + public TextureImporterFormat iosFormat = TextureImporterFormat.ASTC_5x5; + public TextureImporterFormat webglFormat = TextureImporterFormat.ASTC_6x6; + + [Header("PackingSetting")] + public int padding = 2; + + public bool enableRotation = true; + public int blockOffset = 1; + public bool tightPacking = true; + + [Header("其他设置")] + [Range(0, 100)] + public int compressionQuality = 50; + + public bool autoGenerate = true; + public bool enableLogging = true; + public bool enableV2 = true; + + [Header("排除关键词")] + public string[] excludeKeywords = { "_Delete", "_Temp" }; + } + +#endif +} \ No newline at end of file diff --git a/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/AtlasConfiguration.cs.meta b/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/AtlasConfiguration.cs.meta new file mode 100644 index 00000000..d78afce5 --- /dev/null +++ b/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/AtlasConfiguration.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f529ff1e114e8ba4cb189f4233102cd5 +timeCreated: 1738748213 \ No newline at end of file diff --git a/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/AtlasEditorWindow.cs b/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/AtlasEditorWindow.cs new file mode 100644 index 00000000..c081f09e --- /dev/null +++ b/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/AtlasEditorWindow.cs @@ -0,0 +1,162 @@ +namespace TEngine.Editor +{ + #if UNITY_EDITOR + using System; + using UnityEditor; + using UnityEngine; + + public class AtlasConfigWindow : EditorWindow + { + [MenuItem("Tools/图集工具/配置面板")] + public static void ShowWindow() + { + GetWindow("Atlas Config").minSize = new Vector2(450, 400); + } + + private Vector2 _scrollPosition; + + private int[] _paddingEnum = new int[] { 2, 4, 8 }; + private bool _showExcludeKeywords = false; // 新增折叠状态变量 + + private void OnGUI() + { + var config = AtlasConfiguration.Instance; + + using (var scrollScope = new EditorGUILayout.ScrollViewScope(_scrollPosition)) + { + _scrollPosition = scrollScope.scrollPosition; + + EditorGUI.BeginChangeCheck(); + + DrawFolderSettings(config); + DrawPlatformSettings(config); + DrawPackingSettings(config); + DrawAdvancedSettings(config); + + if (EditorGUI.EndChangeCheck()) + { + AtlasConfiguration.Save(true); + AssetDatabase.Refresh(); + } + + DrawActionButtons(); + } + } + + private void DrawFolderSettings(AtlasConfiguration config) + { + GUILayout.Label("目录设置", EditorStyles.boldLabel); + config.outputAtlasDir = DrawFolderField("输出目录", config.outputAtlasDir); + config.sourceAtlasRoot = DrawFolderField("收集目录", config.sourceAtlasRoot); + config.excludeFolder = DrawFolderField("排除目录", config.excludeFolder); + EditorGUILayout.Space(); + } + + private string DrawFolderField(string label, string path) + { + using (new EditorGUILayout.HorizontalScope()) + { + path = EditorGUILayout.TextField(label, path); + if (GUILayout.Button("选择", GUILayout.Width(60))) + { + var newPath = EditorUtility.OpenFolderPanel(label, Application.dataPath, ""); + if (!string.IsNullOrEmpty(newPath)) + { + path = "Assets" + newPath.Substring(Application.dataPath.Length); + } + } + } + + return path; + } + + private void DrawPlatformSettings(AtlasConfiguration config) + { + GUILayout.Label("平台设置", EditorStyles.boldLabel); + config.androidFormat = (TextureImporterFormat)EditorGUILayout.EnumPopup("Android 格式", config.androidFormat); + config.iosFormat = (TextureImporterFormat)EditorGUILayout.EnumPopup("iOS 格式", config.iosFormat); + config.webglFormat = (TextureImporterFormat)EditorGUILayout.EnumPopup("WebGL 格式", config.webglFormat); + config.compressionQuality = EditorGUILayout.IntSlider("压缩质量", config.compressionQuality, 0, 100); + EditorGUILayout.Space(); + } + + private void DrawPackingSettings(AtlasConfiguration config) + { + GUILayout.Label("PackingSetting", EditorStyles.boldLabel); + config.padding = EditorGUILayout.IntPopup("Padding", + config.padding, + Array.ConvertAll(_paddingEnum, x => x.ToString()), + _paddingEnum); + config.blockOffset = EditorGUILayout.IntField("BlockOffset", config.blockOffset); + config.enableRotation = EditorGUILayout.Toggle("Enable Rotation", config.enableRotation); + config.tightPacking = EditorGUILayout.Toggle("剔除透明区域", config.tightPacking); + EditorGUILayout.Space(); + } + + + private void DrawAdvancedSettings(AtlasConfiguration config) + { + GUILayout.Label("高级设置", EditorStyles.boldLabel); + config.autoGenerate = EditorGUILayout.Toggle("自动生成", config.autoGenerate); + config.enableLogging = EditorGUILayout.Toggle("启用日志", config.enableLogging); + config.enableV2 = EditorGUILayout.Toggle("启用V2打包", config.enableV2); + // 优化后的排除关键词显示 + _showExcludeKeywords = EditorGUILayout.BeginFoldoutHeaderGroup(_showExcludeKeywords, "排除关键词"); + if (_showExcludeKeywords) + { + int keywordCount = config.excludeKeywords?.Length ?? 0; + int newCount = EditorGUILayout.IntField("数量", keywordCount); + + // 调整数组大小 + if (newCount != keywordCount) + { + Array.Resize(ref config.excludeKeywords, newCount); + } + + // 绘制每个元素 + for (int i = 0; i < newCount; i++) + { + config.excludeKeywords[i] = EditorGUILayout.TextField($"关键词 {i + 1}", + config.excludeKeywords[i] ?? ""); + } + + // 添加快捷按钮 + EditorGUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("添加", GUILayout.Width(60))) + { + Array.Resize(ref config.excludeKeywords, newCount + 1); + } + + if (GUILayout.Button("清空", GUILayout.Width(60))) + { + config.excludeKeywords = Array.Empty(); + } + + EditorGUILayout.EndHorizontal(); + } + + EditorGUILayout.EndFoldoutHeaderGroup(); + + EditorGUILayout.Space(); + } + + private void DrawActionButtons() + { + using (new EditorGUILayout.HorizontalScope()) + { + if (GUILayout.Button("立即生成所有图集", GUILayout.Height(30))) + { + EditorSpriteSaveInfo.ForceGenerateAll(); + } + + if (GUILayout.Button("清空缓存", GUILayout.Height(30))) + { + EditorSpriteSaveInfo.ClearCache(); + } + } + } + } + +#endif +} \ No newline at end of file diff --git a/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/AtlasEditorWindow.cs.meta b/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/AtlasEditorWindow.cs.meta new file mode 100644 index 00000000..ae068394 --- /dev/null +++ b/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/AtlasEditorWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5a0f8acf9a5e4034f9f28fc384c5ce89 +timeCreated: 1738748236 \ No newline at end of file diff --git a/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/EditorSpriteSaveInfo.cs b/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/EditorSpriteSaveInfo.cs new file mode 100644 index 00000000..17724fb4 --- /dev/null +++ b/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/EditorSpriteSaveInfo.cs @@ -0,0 +1,361 @@ +namespace TEngine.Editor +{ + #if UNITY_EDITOR + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using UnityEditor; + using UnityEditor.U2D; + using UnityEngine; + using UnityEngine.U2D; + + public static class EditorSpriteSaveInfo + { + private static readonly HashSet _dirtyAtlasNames = new HashSet(); + private static readonly Dictionary> _atlasMap = new Dictionary>(); + private static bool _initialized; + + private static AtlasConfiguration Config => AtlasConfiguration.Instance; + + static EditorSpriteSaveInfo() + { + EditorApplication.update += OnUpdate; + Initialize(); + } + + private static void Initialize() + { + if (_initialized) return; + + ScanExistingSprites(); + _initialized = true; + } + + public static void OnImportSprite(string assetPath) + { + if (!ShouldProcess(assetPath)) return; + + var atlasName = GetAtlasName(assetPath); + if (string.IsNullOrEmpty(atlasName)) return; + + if (!_atlasMap.TryGetValue(atlasName, out var list)) + { + list = new List(); + _atlasMap[atlasName] = list; + } + + if (!list.Contains(assetPath)) + { + list.Add(assetPath); + MarkDirty(atlasName); + MarkParentAtlasesDirty(assetPath); + } + } + + public static void OnDeleteSprite(string assetPath) + { + if (!ShouldProcess(assetPath)) return; + + var atlasName = GetAtlasName(assetPath); + if (string.IsNullOrEmpty(atlasName)) return; + + if (_atlasMap.TryGetValue(atlasName, out var list)) + { + if (list.Remove(assetPath)) + { + MarkDirty(atlasName); + MarkParentAtlasesDirty(assetPath); + } + } + } + + [MenuItem("Tools/图集工具/ForceGenerateAll")] + public static void ForceGenerateAll() + { + _atlasMap.Clear(); + ScanExistingSprites(); + _dirtyAtlasNames.UnionWith(_atlasMap.Keys); + ProcessDirtyAtlases(true); + } + + public static void ClearCache() + { + _dirtyAtlasNames.Clear(); + _atlasMap.Clear(); + AssetDatabase.Refresh(); + } + + public static void MarkParentAtlasesDirty(string assetPath) + { + var currentPath = Path.GetDirectoryName(assetPath); + var rootPath = Config.sourceAtlasRoot.Replace("\\", "/").TrimEnd('/'); + + while (currentPath != null && currentPath.StartsWith(rootPath)) + { + var parentAtlasName = GetAtlasNameForDirectory(currentPath); + if (!string.IsNullOrEmpty(parentAtlasName)) + { + MarkDirty(parentAtlasName); + } + + currentPath = Path.GetDirectoryName(currentPath); + } + } + + private static void OnUpdate() + { + if (_dirtyAtlasNames.Count > 0) + { + ProcessDirtyAtlases(); + } + } + + private static void ProcessDirtyAtlases(bool force = false) + { + try + { + AssetDatabase.StartAssetEditing(); + + foreach (var atlasName in _dirtyAtlasNames.ToList()) + { + if (force || ShouldUpdateAtlas(atlasName)) + { + GenerateAtlas(atlasName); + } + + _dirtyAtlasNames.Remove(atlasName); + } + } + finally + { + AssetDatabase.StopAssetEditing(); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + } + } + + private static void GenerateAtlas(string atlasName) + { + var outputPath = $"{Config.outputAtlasDir}/{atlasName}.spriteatlas"; + SpriteAtlasAsset spriteAtlasAsset = default; + SpriteAtlas atlas = new SpriteAtlas(); + if (Config.enableV2) + { + outputPath = $"{Config.outputAtlasDir}/{atlasName}.spriteatlasv2"; + if (!File.Exists(outputPath)) + { + spriteAtlasAsset = new SpriteAtlasAsset(); + } + else + { + spriteAtlasAsset = SpriteAtlasAsset.Load(outputPath); + atlas = AssetDatabase.LoadAssetAtPath(outputPath); + if (atlas != null) + { + var olds = atlas.GetPackables(); + if (olds != null) spriteAtlasAsset.Remove(olds); + } + } + } + + + var sprites = LoadValidSprites(atlasName); + EnsureOutputDirectory(); + if (sprites.Count == 0) + { + DeleteAtlas(outputPath); + return; + } + + if (Config.enableV2) + { + spriteAtlasAsset.Add(sprites.ToArray()); + SpriteAtlasAsset.Save(spriteAtlasAsset, outputPath); + AssetDatabase.Refresh(); + SpriteAtlasImporter sai = (SpriteAtlasImporter)AssetImporter.GetAtPath(outputPath); + ConfigureAtlasV2Settings(sai); + AssetDatabase.WriteImportSettingsIfDirty(outputPath); + } + else + { + ConfigureAtlasSettings(atlas); + atlas.Add(sprites.ToArray()); + atlas.SetIsVariant(false); + AssetDatabase.CreateAsset(atlas, outputPath); + } + + + if (Config.enableLogging) + Debug.Log($"Generated atlas: {atlasName} ({sprites.Count} sprites)"); + } + + private static List LoadValidSprites(string atlasName) + { + return _atlasMap[atlasName] + .Where(File.Exists) + .Select(p => AssetDatabase.LoadAssetAtPath(p)) + .Where(s => s != null) + .ToList(); + } + + private static void ConfigureAtlasV2Settings(SpriteAtlasImporter atlasImporter) + { + void SetPlatform(string platform, TextureImporterFormat format) + { + var settings = atlasImporter.GetPlatformSettings(platform); + if (settings == null) return; + ; + settings.overridden = true; + settings.format = format; + settings.compressionQuality = Config.compressionQuality; + atlasImporter.SetPlatformSettings(settings); + } + + SetPlatform("Android", Config.androidFormat); + SetPlatform("iPhone", Config.iosFormat); + SetPlatform("WebGL", Config.webglFormat); + + var packingSettings = new SpriteAtlasPackingSettings + { + padding = Config.padding, + enableRotation = Config.enableRotation, + blockOffset = Config.blockOffset, + enableTightPacking = Config.tightPacking, + enableAlphaDilation = true + }; + atlasImporter.packingSettings = packingSettings; + } + + private static void ConfigureAtlasSettings(SpriteAtlas atlas) + { + void SetPlatform(string platform, TextureImporterFormat format) + { + var settings = atlas.GetPlatformSettings(platform); + settings.overridden = true; + settings.format = format; + settings.compressionQuality = Config.compressionQuality; + atlas.SetPlatformSettings(settings); + } + + SetPlatform("Android", Config.androidFormat); + SetPlatform("iPhone", Config.iosFormat); + SetPlatform("WebGL", Config.webglFormat); + + var packingSettings = new SpriteAtlasPackingSettings + { + padding = Config.padding, + enableRotation = Config.enableRotation, + blockOffset = Config.blockOffset, + }; + atlas.SetPackingSettings(packingSettings); + } + + private static string GetAtlasName(string assetPath) + { + var normalizedPath = assetPath.Replace("\\", "/"); + var rootPath = Config.sourceAtlasRoot.Replace("\\", "/").TrimEnd('/'); + + if (!normalizedPath.StartsWith(rootPath + "/")) return null; + + var relativePath = normalizedPath + .Substring(rootPath.Length + 1) + .Split('/'); + + if (relativePath.Length < 2) return null; + + var directories = relativePath.Take(relativePath.Length - 1); + var atlasNamePart = string.Join("_", directories); + var rootFolderName = Path.GetFileName(rootPath); + + return $"{rootFolderName}_{atlasNamePart}"; + } + + private static bool ShouldProcess(string assetPath) + { + return IsImageFile(assetPath) && !IsExcluded(assetPath); + } + + private static bool IsExcluded(string path) + { + return path.StartsWith(Config.excludeFolder) || + Config.excludeKeywords.Any(k => path.IndexOf(k, StringComparison.OrdinalIgnoreCase) >= 0); + } + + private static bool IsImageFile(string path) + { + var ext = Path.GetExtension(path).ToLower(); + return ext == ".png" || ext == ".jpg" || ext == ".jpeg"; + } + + private static void MarkDirty(string atlasName) + { + _dirtyAtlasNames.Add(atlasName); + } + + private static bool ShouldUpdateAtlas(string atlasName) + { + // var outputPath = $"{Config.outputAtlasDir}/{atlasName}.spriteatlas"; + return true; + } + + private static DateTime GetLatestSpriteTime(string atlasName) + { + return _atlasMap[atlasName] + .Select(p => new FileInfo(p).LastWriteTime) + .DefaultIfEmpty() + .Max(); + } + + private static void DeleteAtlas(string path) + { + if (File.Exists(path)) + { + AssetDatabase.DeleteAsset(path); + if (Config.enableLogging) + Debug.Log($"Deleted empty atlas: {Path.GetFileName(path)}"); + } + } + + private static void EnsureOutputDirectory() + { + if (!Directory.Exists(Config.outputAtlasDir)) + { + Directory.CreateDirectory(Config.outputAtlasDir); + AssetDatabase.Refresh(); + } + } + + private static void ScanExistingSprites() + { + var guids = AssetDatabase.FindAssets("t:Sprite", new[] { Config.sourceAtlasRoot }); + foreach (var guid in guids) + { + var path = AssetDatabase.GUIDToAssetPath(guid); + if (ShouldProcess(path)) + { + OnImportSprite(path); + } + } + } + + private static string GetAtlasNameForDirectory(string directoryPath) + { + var normalizedPath = directoryPath.Replace("\\", "/"); + var rootPath = Config.sourceAtlasRoot.Replace("\\", "/").TrimEnd('/'); + + if (!normalizedPath.StartsWith(rootPath + "/")) return null; + + var relativePath = normalizedPath + .Substring(rootPath.Length + 1) + .Split('/'); + + var atlasNamePart = string.Join("_", relativePath); + var rootFolderName = Path.GetFileName(rootPath); + + return $"{rootFolderName}_{atlasNamePart}"; + } + } + +#endif +} \ No newline at end of file diff --git a/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/EditorSpriteSaveInfo.cs.meta b/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/EditorSpriteSaveInfo.cs.meta new file mode 100644 index 00000000..c78628d6 --- /dev/null +++ b/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/EditorSpriteSaveInfo.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6e0aa32db2943f742a839708e928fda4 +timeCreated: 1738748262 \ No newline at end of file diff --git a/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/SpritePostprocessor.cs b/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/SpritePostprocessor.cs new file mode 100644 index 00000000..cfe78e48 --- /dev/null +++ b/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/SpritePostprocessor.cs @@ -0,0 +1,137 @@ +using System; +using System.IO; + +namespace TEngine.Editor +{ + using UnityEditor; + using UnityEngine; + + public class SpritePostprocessor : AssetPostprocessor + { + private static void OnPostprocessAllAssets( + string[] importedAssets, + string[] deletedAssets, + string[] movedAssets, + string[] movedFromAssetPaths) + { + var config = AtlasConfiguration.Instance; + + if (!config.autoGenerate) return; + + try + { + ProcessAssetChanges( + importedAssets: importedAssets, + deletedAssets: deletedAssets, + movedAssets: movedAssets, + movedFromPaths: movedFromAssetPaths + ); + } + catch (Exception e) + { + Debug.LogError($"Atlas processing error: {e.Message}\n{e.StackTrace}"); + } + finally + { + AssetDatabase.Refresh(); + } + } + + private static void ProcessAssetChanges( + string[] importedAssets, + string[] deletedAssets, + string[] movedAssets, + string[] movedFromPaths) + { + ProcessAssets(importedAssets, (path) => + { + EditorSpriteSaveInfo.OnImportSprite(path); + LogProcessed("[Added]", path); + }); + + ProcessAssets(deletedAssets, (path) => + { + EditorSpriteSaveInfo.OnDeleteSprite(path); + LogProcessed("[Deleted]", path); + }); + + ProcessMovedAssets(movedFromPaths, movedAssets); + } + + private static void ProcessAssets(string[] assets, Action processor) + { + if (assets == null) return; + + foreach (var asset in assets) + { + if (ShouldProcessAsset(asset)) + { + processor?.Invoke(asset); + } + } + } + + private static void ProcessMovedAssets(string[] oldPaths, string[] newPaths) + { + if (oldPaths == null || newPaths == null) return; + + for (int i = 0; i < oldPaths.Length; i++) + { + if (ShouldProcessAsset(oldPaths[i])) + { + EditorSpriteSaveInfo.OnDeleteSprite(oldPaths[i]); + LogProcessed("[Moved From]", oldPaths[i]); + EditorSpriteSaveInfo.MarkParentAtlasesDirty(oldPaths[i]); + } + + if (ShouldProcessAsset(newPaths[i])) + { + EditorSpriteSaveInfo.OnImportSprite(newPaths[i]); + LogProcessed("[Moved To]", newPaths[i]); + EditorSpriteSaveInfo.MarkParentAtlasesDirty(newPaths[i]); + } + } + } + + private static bool ShouldProcessAsset(string assetPath) + { + var config = AtlasConfiguration.Instance; + + if (string.IsNullOrEmpty(assetPath)) return false; + if (assetPath.StartsWith("Packages/")) return false; + + if (!assetPath.StartsWith(config.sourceAtlasRoot)) return false; + if (assetPath.StartsWith(config.excludeFolder)) return false; + + if (!IsValidImageFile(assetPath)) return false; + + foreach (var keyword in config.excludeKeywords) + { + if (assetPath.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) >= 0) + return false; + } + + return true; + } + + private static bool IsValidImageFile(string path) + { + var ext = Path.GetExtension(path).ToLower(); + return ext switch + { + ".png" => true, + ".jpg" => true, + ".jpeg" => true, + _ => false + }; + } + + private static void LogProcessed(string operation, string path) + { + if (AtlasConfiguration.Instance.enableLogging) + { + Debug.Log($"{operation} {Path.GetFileName(path)}\nPath: {path}"); + } + } + } +} \ No newline at end of file diff --git a/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/SpritePostprocessor.cs.meta b/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/SpritePostprocessor.cs.meta new file mode 100644 index 00000000..50151641 --- /dev/null +++ b/UnityProject/Assets/TEngine/Editor/AtlasMakerEditor/SpritePostprocessor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e5d969d76e1a36445810f61bafc4f7db +timeCreated: 1738748276 \ No newline at end of file diff --git a/UnityProject/Assets/TEngine/Editor/Postprocessor.meta b/UnityProject/Assets/TEngine/Editor/Postprocessor.meta deleted file mode 100644 index 34397b25..00000000 --- a/UnityProject/Assets/TEngine/Editor/Postprocessor.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 531cb4efe9b94a558716c7ef8a401f8b -timeCreated: 1705976900 \ No newline at end of file diff --git a/UnityProject/Assets/TEngine/Editor/Postprocessor/SpritePostprocessor.cs b/UnityProject/Assets/TEngine/Editor/Postprocessor/SpritePostprocessor.cs deleted file mode 100644 index 34e68e6e..00000000 --- a/UnityProject/Assets/TEngine/Editor/Postprocessor/SpritePostprocessor.cs +++ /dev/null @@ -1,543 +0,0 @@ -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 NORMAL_ATLAS_DIR = "Assets/AssetArt/Atlas"; - private const string UI_SPRITE_PATH = "Assets/AssetRaw/UIRaw"; - private const string UI_ATLAS_PATH = "Assets/AssetRaw/UIRaw/Atlas"; - private static readonly List _dirtyAtlasList = new List(); - private static readonly Dictionary> _allASprites = new Dictionary>(); - private static readonly Dictionary _uiAtlasMap = new Dictionary(); - private static bool _isInit = false; - private static bool _dirty = false; - - public static void Init() - { - if (_isInit) - { - return; - } - - EditorApplication.update += CheckDirty; - - //读取所有图集信息 - string[] findAssets = AssetDatabase.FindAssets("t:SpriteAtlas", new[] { NORMAL_ATLAS_DIR }); - foreach (var findAsset in findAssets) - { - var path = AssetDatabase.GUIDToAssetPath(findAsset); - SpriteAtlas sa = AssetDatabase.LoadAssetAtPath(path, typeof(SpriteAtlas)) as SpriteAtlas; - if (sa == null) - { - Debug.LogError($"加载图集数据{path}失败"); - continue; - } - - string atlasName = Path.GetFileNameWithoutExtension(path); - var objects = sa.GetPackables(); - foreach (var o in objects) - { - if (!_allASprites.TryGetValue(atlasName, out var list)) - { - list = new List(); - _allASprites.Add(atlasName, list); - } - - list.Add(AssetDatabase.GetAssetPath(o)); - } - } - - _isInit = true; - } - - public static void CheckDirty() - { - if (_dirty) - { - _dirty = false; - - AssetDatabase.Refresh(); - float lastProgress = -1; - for (int i = 0; i < _dirtyAtlasList.Count; i++) - { - string atlasName = _dirtyAtlasList[i]; - Debug.Log("更新图集 : " + atlasName); - var curProgress = (float)i / _dirtyAtlasList.Count; - if (curProgress > lastProgress + 0.01f) - { - lastProgress = curProgress; - var progressText = $"当前进度:{i}/{_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(); - _dirtyAtlasList.Clear(); - } - } - - public static void OnImportSprite(string assetPath) - { - if (!assetPath.StartsWith(UI_SPRITE_PATH)) - { - return; - } - - TextureImporter ti = AssetImporter.GetAtPath(assetPath) as TextureImporter; - - if (ti != null) - { - var modify = false; - - if (assetPath.StartsWith(UI_SPRITE_PATH)) - { - 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; - andPlatformSettings.compressionQuality = 50; - 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; - } - - //调整WebGL格式 - var webglSettings = ti.GetPlatformTextureSettings("WebGL"); - if (!webglSettings.overridden) - { - webglSettings.overridden = true; - modify = true; - } - - if (webglSettings.format != TextureImporterFormat.ASTC_6x6) - { - webglSettings.format = TextureImporterFormat.ASTC_6x6; - webglSettings.compressionQuality = 50; - ti.SetPlatformTextureSettings(webglSettings); - 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(".", StringComparison.Ordinal)); - 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 (!_uiAtlasMap.TryGetValue(spriteName, out string oldAssetPath) || spritePath == oldAssetPath) - { - _uiAtlasMap[spriteName] = spritePath; - _dirty = true; - } - else - { - Debug.LogError($"有重名的图片:{spriteName}\n旧图集:{oldAssetPath}\n新图集:{spritePath} "); - _uiAtlasMap[spriteName] = spritePath; - _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 - { - if (!_allASprites.TryGetValue(atlasName, out var ret)) - { - ret = new List(); - _allASprites.Add(atlasName, ret); - } - - if (!ret.Contains(assetPath)) - { - ret.Add(assetPath); - _dirty = true; - if (!_dirtyAtlasList.Contains(atlasName)) - { - _dirtyAtlasList.Add(atlasName); - } - } - } - } - - public static void OnDeleteSprite(string assetPath) - { - if (assetPath.StartsWith("Assets/UIRaw_Delete")) - { - return; - } - - if (!assetPath.StartsWith(UI_SPRITE_PATH)) - { - return; - } - - Init(); - string atlasName = GetPackageTag(assetPath); - if (!_allASprites.TryGetValue(atlasName, out var ret)) - { - return; - } - - if (!ret.Exists(s => Path.GetFileName(s) == Path.GetFileName(assetPath))) - { - return; - } - - if (assetPath.StartsWith(UI_SPRITE_PATH)) - { - var spriteName = Path.GetFileNameWithoutExtension(assetPath); - if (_uiAtlasMap.ContainsKey(spriteName)) - { - _uiAtlasMap.Remove(spriteName); - _dirty = true; - } - } - - ret.Remove(assetPath); - _dirty = true; - if (!_dirtyAtlasList.Contains(atlasName)) - { - _dirtyAtlasList.Add(atlasName); - } - } - - #region 更新图集 - - public static void SaveAtlas(string atlasName, bool isUI) - { - List spriteList = new List(); - if (_allASprites.TryGetValue(atlasName, out var list)) - { - list.Sort(StringComparer.Ordinal); - - foreach (var s in list) - { - var sprite = AssetDatabase.LoadAssetAtPath(s); - if (sprite != null) - { - spriteList.Add(sprite); - } - } - } - - var path = $"{NORMAL_ATLAS_DIR}/{atlasName}.spriteatlas"; - - if (spriteList.Count == 0) - { - if (File.Exists(path)) - { - AssetDatabase.DeleteAsset(path); - } - - return; - } - - var atlas = new SpriteAtlas(); - // var atlas = new SpriteAtlasAsset(); - 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 = TextureImporterFormat.ASTC_5x5; - iphonePlatformSetting.compressionQuality = 100; - atlas.SetPlatformSettings(iphonePlatformSetting); - } - - var androidPlatformSetting = atlas.GetPlatformSettings("Android"); - if (!androidPlatformSetting.overridden) - { - androidPlatformSetting.overridden = true; - androidPlatformSetting.format = TextureImporterFormat.ASTC_6x6; - androidPlatformSetting.compressionQuality = 100; - atlas.SetPlatformSettings(androidPlatformSetting); - } - - var webglSettings = atlas.GetPlatformSettings("WebGL"); - if (!webglSettings.overridden) - { - webglSettings.overridden = true; - webglSettings.format = TextureImporterFormat.ASTC_6x6; - webglSettings.compressionQuality = 50; - atlas.SetPlatformSettings(webglSettings); - } - - atlas.SetPackingSettings(setting); - atlas.Add(spriteList.ToArray()); - - AssetDatabase.CreateAsset(atlas, path); - AssetDatabase.SaveAssets(); - AssetDatabase.Refresh(); - } - - #endregion - - #region 重新生成图集 - - private static readonly Dictionary> _tempAllASprites = new Dictionary>(); - - [MenuItem("TEngine/Atlas/重新生成UI图集", false, 90)] - static void ForceGenAtlas() - { - Init(); - List needSaveAtlas = new List(); - _tempAllASprites.Clear(); - _allASprites.Clear(); - var findAssets = AssetDatabase.FindAssets("t:sprite", new[] { UI_ATLAS_PATH }); - foreach (var findAsset in findAssets) - { - var path = AssetDatabase.GUIDToAssetPath(findAsset); - var atlasName = GetPackageTag(path); - if (!_tempAllASprites.TryGetValue(atlasName, out var spriteList)) - { - spriteList = new List(); - _tempAllASprites[atlasName] = spriteList; - } - - if (!spriteList.Contains(path)) - { - spriteList.Add(path); - } - } - - //有变化的才刷 - var iter = _tempAllASprites.GetEnumerator(); - while (iter.MoveNext()) - { - bool needSave = false; - var atlasName = iter.Current.Key; - var newSpritesList = iter.Current.Value; - - if (_allASprites.TryGetValue(atlasName, out var 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; - _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 diff --git a/UnityProject/Assets/TEngine/Editor/Postprocessor/SpritePostprocessor.cs.meta b/UnityProject/Assets/TEngine/Editor/Postprocessor/SpritePostprocessor.cs.meta deleted file mode 100644 index 7d03fe8d..00000000 --- a/UnityProject/Assets/TEngine/Editor/Postprocessor/SpritePostprocessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 0b37506bd00c3f14d83f966ae20ba8ec -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/ProjectSettings/AtlasConfiguration.asset b/UnityProject/ProjectSettings/AtlasConfiguration.asset new file mode 100644 index 00000000..0e60137b --- /dev/null +++ b/UnityProject/ProjectSettings/AtlasConfiguration.asset @@ -0,0 +1,31 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f529ff1e114e8ba4cb189f4233102cd5, type: 3} + m_Name: + m_EditorClassIdentifier: + outputAtlasDir: Assets/AssetArt/Atlas + sourceAtlasRoot: Assets/AssetRaw/UIRaw/Atlas + excludeFolder: Assets/AssetRaw/UIRaw/Raw + androidFormat: 50 + iosFormat: 49 + webglFormat: 50 + padding: 4 + enableRotation: 1 + blockOffset: 1 + tightPacking: 1 + compressionQuality: 50 + autoGenerate: 1 + enableLogging: 1 + enableV2: 1 + excludeKeywords: + - _Delete + - _Temp