using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using UnityEditor;
using UnityEngine;
///
/// 一键修复图集"渗色 / 串图 / 边缘被邻居图片填充"问题。
///
/// 症状:圆形等带透明边缘的图片,四周被其他图片的像素填充;正方形区域采样/裁剪时会取到邻居图。
/// 成因:padding 过小 + 紧致打包(透明边被裁掉) + 未开 Alpha 扩张 + 图集可能被降采样。
///
/// 本工具对图集的 packingSettings 统一设置:
/// padding 4 → 8 相邻 sprite 之间留出大于压缩块的间隙
/// enableTightPacking off 不再裁掉透明边,sprite 保持完整矩形(正方形区域只含自己)
/// enableRotation off 不在图集内旋转贴图,避免采样方向错乱(串图)
/// enableAlphaDilation on 边缘颜色向外扩张,滤色采样不会取到邻居像素
///
/// 改完必须:重建 Addressables 内容 → 重出包。
///
public static class AtlasPackingFix
{
private const int Padding = 8;
private const bool KeepRotation = false; // 需要省图集空间时可改回 true
[MenuItem("Tools/图集工具/修复所有图集(渗色·串图)")]
public static void FixAll()
{
var list = new List();
foreach (var f in Directory.GetFiles("Assets", "*.spriteatlasv2", SearchOption.AllDirectories))
list.Add(f.Replace('\\', '/'));
foreach (var f in Directory.GetFiles("Assets", "*.spriteatlas", SearchOption.AllDirectories))
list.Add(f.Replace('\\', '/'));
if (list.Count == 0) { Debug.LogWarning("[图集修复] 没找到任何图集"); return; }
Apply(list);
}
[MenuItem("Tools/图集工具/修复选中图集(渗色·串图)")]
public static void FixSelected()
{
var list = new List();
foreach (var guid in Selection.assetGUIDs)
{
var p = AssetDatabase.GUIDToAssetPath(guid);
if (p.EndsWith(".spriteatlas") || p.EndsWith(".spriteatlasv2"))
list.Add(p);
}
if (list.Count == 0)
{
Debug.LogWarning("[图集修复] 请先在 Project 里选中至少一个 .spriteatlas / .spriteatlasv2");
return;
}
Apply(list);
}
private static void Apply(List paths)
{
int ok = 0, skip = 0;
try
{
AssetDatabase.StartAssetEditing();
foreach (var path in paths)
{
var importer = AssetImporter.GetAtPath(path);
if (importer == null) { skip++; continue; }
// 用反射拿 packingSettings,避免不同 Unity 版本字段可见性差异导致编译问题
var prop = importer.GetType().GetProperty("packingSettings");
if (prop == null || !prop.CanRead || !prop.CanWrite)
{
Debug.LogWarning($"[图集修复] 跳过(无 packingSettings): {path}");
skip++;
continue;
}
object boxed = prop.GetValue(importer); // 装箱的结构体副本
var st = boxed.GetType();
SetField(st, boxed, "padding", Padding);
SetField(st, boxed, "enableTightPacking", false);
SetField(st, boxed, "enableRotation", KeepRotation);
SetField(st, boxed, "enableAlphaDilation", true);
prop.SetValue(importer, boxed);
importer.SaveAndReimport();
ok++;
Debug.Log($"[图集修复] {Path.GetFileName(path)} → padding={Padding}, TightPacking=off, Rotation={(KeepRotation ? "on" : "off")}, AlphaDilation=on");
}
}
finally
{
AssetDatabase.StopAssetEditing();
AssetDatabase.Refresh();
}
Debug.Log($"[图集修复] 完成:处理 {ok} 个,跳过 {skip} 个。请重建 Addressables 内容后重出包。");
}
private static void SetField(Type t, object boxed, string name, object value)
{
var f = t.GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (f != null) f.SetValue(boxed, value);
else Debug.LogWarning($"[图集修复] 字段不存在,已跳过: {name}");
}
}