#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using HotUpdate.UI;
using UnityEditor;
using UnityEditor.U2D;
using UnityEngine;
using UnityEngine.U2D;
using Object = UnityEngine.Object;
namespace AIGame.EditorTools
{
/// 移植 ClientTrunk SpriteAtalsGenerator 的按目录打图集规则,增量维护并保留 GUID。
public static class UiSpriteAtlasGenerator
{
public const string GeneratedLabel = "AIGame.UI.GeneratedAtlas";
private static bool s_Busy;
[MenuItem("Tools/UI/Generate Sprite Atlases")]
public static void GenerateFromMenu()
{
Debug.Log("[UIAtlas] " + GenerateAll());
}
public static string GenerateAll()
{
if (s_Busy) return "Generation already in progress.";
if (EditorApplication.isPlayingOrWillChangePlaymode)
throw new InvalidOperationException("Generate UI atlases in Edit Mode.");
s_Busy = true;
try
{
var groups = CollectTextures();
EnsureFolder(UiAtlasPaths.AtlasRoot);
// V1 matches the reference project and supports SpriteAtlas late binding in bundles.
if (EditorSettings.spritePackerMode != SpritePackerMode.AlwaysOnAtlas)
EditorSettings.spritePackerMode = SpritePackerMode.AlwaysOnAtlas;
int changed = 0, deleted = 0;
foreach (var group in groups)
{
string path = group.Key;
var atlas = AssetDatabase.LoadAssetAtPath(path);
bool created = atlas == null;
if (created)
{
atlas = new SpriteAtlas();
AssetDatabase.CreateAsset(atlas, path);
}
bool dirty = Configure(atlas, group.Value.ToArray()) || created;
var labels = AssetDatabase.GetLabels(atlas);
if (!labels.Contains(GeneratedLabel))
{
AssetDatabase.SetLabels(atlas, labels.Concat(new[] { GeneratedLabel }).ToArray());
dirty = true;
}
if (!dirty) continue;
EditorUtility.SetDirty(atlas);
AssetDatabase.SaveAssetIfDirty(atlas);
changed++;
}
foreach (string guid in AssetDatabase.FindAssets("l:" + GeneratedLabel, new[] { UiAtlasPaths.AtlasRoot }))
{
string path = AssetDatabase.GUIDToAssetPath(guid);
if (groups.ContainsKey(path) || !path.EndsWith(".spriteatlas", StringComparison.Ordinal)) continue;
if (!AssetDatabase.DeleteAsset(path)) throw new IOException("Cannot remove stale UI atlas: " + path);
deleted++;
}
return $"atlases={groups.Count}, textures={groups.Values.Sum(g => g.Count)}, updated={changed}, removed={deleted}";
}
finally { s_Busy = false; }
}
public static SortedDictionary> CollectTextures()
{
var groups = new SortedDictionary>(StringComparer.Ordinal);
var names = new Dictionary>(StringComparer.Ordinal);
if (!AssetDatabase.IsValidFolder(UiAtlasPaths.TextureRoot)) return groups;
foreach (string path in AssetDatabase.FindAssets("t:Texture2D", new[] { UiAtlasPaths.TextureRoot })
.Select(AssetDatabase.GUIDToAssetPath).OrderBy(p => p, StringComparer.Ordinal))
{
var importer = AssetImporter.GetAtPath(path) as TextureImporter;
if (importer == null || importer.textureType != TextureImporterType.Sprite)
throw new InvalidOperationException("UI atlas input must be a Sprite: " + path);
string atlasPath = UiAtlasPaths.GetAtlasPathForTexture(path);
if (!groups.TryGetValue(atlasPath, out var textures))
{
groups.Add(atlasPath, textures = new List