using System.Text;
using UnityEditor;
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
using UnityEngine;
///
/// AA 依赖链修复迁移工具(一次性)。
///
/// 【背景】Addressables 加载 bundle 时会递归加载其依赖 bundle,而构建报告显示存在
/// 跨玩法依赖链,导致"未登录就加载鱼包 / 进 A 玩法拉 B 玩法鱼包":
/// defaultlocalgroup → fish_xjmh → fish_hhwk (启动链:默认音频一碰 D LG 全链拖入)
/// fish_flzy → fish_hhwk (进 FLZY 房拉 HHWK 鱼包)
/// gameuires → fish_xjmh (进任何房间拉 XJMH 鱼包)
///
/// 【修复内容】(对应 2026-10-08 16:41 构建报告分析出的确切依赖边)
/// 1. PW_Enemy_4000.prefab(XJMH Boss,误在 D LG)→ Fish_XJMH 组 断 D LG→fish_xjmh
/// 2. XJMHCreateFish.asset(XJMH 配置,误在 D LG)→ Fish_XJMH 组
/// 3. 新建 SharedRes 组:Game177_baigujing.png(HHWK 图鉴贴图被 XJMH 小丑扑克引用)、
/// fish_4003 Variant.png(HHWK 图鉴贴图被 FLZY 闪电引用)→ SharedRes
/// 断 fish_xjmh→fish_hhwk、fish_flzy→fish_hhwk(两边都只依赖小共享包)
/// 4. GameMainPanelXJMH 引用的 7 个 XJMH 资源(Boss出场特效/帮助Item/技能sprite)
/// → GameUIRes 组 断 gameuires→fish_xjmh
/// (若鱼包资产也引用它们,产生 fish_xjmh→gameuires 边——进房必载面板,无害)
///
/// 【使用】Unity 菜单 Tools → AA依赖修复 → 执行修复并重建Addressables,
/// 完成后用 AABundleMonitor 悬浮窗验证:启动仅 4 个包、进房只加当前玩法鱼包。
///
public static class AAFixDependencyMigration
{
[MenuItem("Tools/AA依赖修复/执行修复并重建Addressables")]
public static void Run()
{
if (!EditorUtility.DisplayDialog("AA依赖修复",
"将执行以下迁移(断掉跨玩法 bundle 依赖链):\n\n" +
"1. PW_Enemy_4000 / XJMHCreateFish → Fish_XJMH 组\n" +
"2. 新建 SharedRes 组,移入 2 张被跨玩法引用的贴图\n" +
"3. GameMainPanelXJMH 引用的 7 个资源 → GameUIRes 组\n\n" +
"迁移完成后可选择立即重建 Addressables。\n继续?",
"执行", "取消"))
return;
var settings = AddressableAssetSettingsDefaultObject.Settings;
if (settings == null)
{
Debug.LogError("[AA依赖修复] 找不到 AddressableAssetSettings");
return;
}
var log = new StringBuilder();
// ---------- ① D LG 里误放的 XJMH 资产 → Fish_XJMH(断 D LG→fish_xjmh 启动链) ----------
var fishXjmh = settings.FindGroup("Fish_XJMH");
if (fishXjmh == null) { Debug.LogError("[AA依赖修复] 找不到 Fish_XJMH 组"); return; }
MoveWithLabels(settings, fishXjmh,
"Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/PW_Enemy_4000.prefab",
new[] { "FishPrefab", "XJMH" }, log);
MoveWithLabels(settings, fishXjmh,
"Assets/MyGame/aa/UI/Game/XJMH/XJMHCreateFish.asset",
new[] { "XJMH" }, log);
// ---------- ② 新建 SharedRes 组,移入被跨玩法引用的贴图(断 xjmh/flzy→hhwk) ----------
var shared = settings.FindGroup("SharedRes");
if (shared == null)
{
shared = CreateGroupLike(settings, "SharedRes", "Fish_XJMH");
log.AppendLine("[组] 已创建 SharedRes(打包配置复制自 Fish_XJMH)");
}
// 保留原 TuJian/HHWK 标签:HHWK 玩法的图鉴 Sprite 交集加载(TuJian+HHWK)仍能命中,
// 只是从 SharedRes 包里取;XJMH/FLZY 对它们的引用改为依赖小共享包
MoveKeepLabels(settings, shared, "Assets/Art/HHWK/res/texture/dynamic/Game177_baigujing.png", log);
MoveKeepLabels(settings, shared, "Assets/Art/HHWK/TuJianTexture/fish_4003 Variant.png", log);
// ---------- ③ GameMainPanelXJMH 引用的资源 → GameUIRes(断 gameuires→fish_xjmh) ----------
var gameUi = settings.FindGroup("GameUIRes");
if (gameUi == null) { Debug.LogError("[AA依赖修复] 找不到 GameUIRes 组"); return; }
string[] guiTargets =
{
"Assets/Art/XJMH/pw/pw_prefab/game/effect/PW_Effect_Boss_Appear.prefab",
"Assets/Art/XJMH/pw/pw_prefab/item/PW_HelpItem1.prefab",
"Assets/Art/XJMH/pw/pw_prefab/item/PW_HelpItem2.prefab",
"Assets/Art/XJMH/pw/pw_prefab/item/PW_SetLockItem.prefab",
"Assets/Art/XJMH/pw/pw_sprite/common/zd_jn_sd.png",
"Assets/Art/XJMH/pw/pw_sprite/common/zd_jn_ss.png",
"Assets/Art/XJMH/pw/pw_sprite/common/zd_jn_zd.png",
};
foreach (var t in guiTargets)
MoveKeepLabels(settings, gameUi, t, log);
AssetDatabase.SaveAssets();
Debug.Log("[AA依赖修复] 迁移完成:\n" + log);
// ---------- ④ 重建 ----------
if (EditorUtility.DisplayDialog("AA依赖修复",
"迁移完成:\n" + log + "\n现在重建 Addressables?(约几分钟)",
"立即重建", "稍后手动重建"))
{
Debug.Log("[AA依赖修复] 开始重建 Addressables...");
AddressableAssetSettings.BuildPlayerContent(out var result);
if (result == null || !string.IsNullOrEmpty(result.Error))
{
Debug.LogError("[AA依赖修复] 构建失败: " + (result != null ? result.Error : "无返回结果"));
EditorUtility.DisplayDialog("AA依赖修复", "构建失败: " + (result != null ? result.Error : "无返回结果"), "确定");
}
else
{
Debug.Log("[AA依赖修复] 构建完成");
EditorUtility.DisplayDialog("AA依赖修复",
"构建完成!\n\n验证步骤:\n" +
"1. Play 启动到登录页 → 悬浮窗应只有 4 个包(builtinshaders/LoginUIRes/DefaultLocalGroup/Turret)\n" +
"2. 进任一玩法房间 → 只新增该玩法的鱼包 + gameuires", "确定");
}
}
}
/// 移动资产到目标组并覆盖标签
private static void MoveWithLabels(AddressableAssetSettings settings, AddressableAssetGroup target,
string path, string[] labels, StringBuilder log)
{
string guid = AssetDatabase.AssetPathToGUID(path);
if (string.IsNullOrEmpty(guid))
{
log.AppendLine("[跳过] 找不到资产: " + path);
return;
}
var entry = settings.CreateOrMoveEntry(guid, target);
if (entry == null)
{
log.AppendLine("[跳过] 移动失败: " + path);
return;
}
entry.labels.Clear();
foreach (var l in labels)
entry.labels.Add(l);
log.AppendLine($"[移动] {path}\n → {target.name}(标签: {string.Join(",", labels)})");
}
/// 移动资产到目标组,保留原有标签
private static void MoveKeepLabels(AddressableAssetSettings settings, AddressableAssetGroup target,
string path, StringBuilder log)
{
string guid = AssetDatabase.AssetPathToGUID(path);
if (string.IsNullOrEmpty(guid))
{
log.AppendLine("[跳过] 找不到资产: " + path);
return;
}
var entry = settings.CreateOrMoveEntry(guid, target);
if (entry == null)
{
log.AppendLine("[跳过] 移动失败: " + path);
return;
}
log.AppendLine($"[移动] {path}\n → {target.name}(保留标签: {string.Join(",", entry.labels)})");
}
/// 按源组的打包配置(BundledAssetGroupSchema/ContentUpdateGroupSchema)创建新组。
/// AddSchema(schema) 内部会复制 schema 并正确挂到新组上,无需手动 CopySerialized。
private static AddressableAssetGroup CreateGroupLike(AddressableAssetSettings settings,
string newName, string srcGroupName)
{
var src = settings.FindGroup(srcGroupName);
var group = settings.CreateGroup(newName, false, false, false, null);
var srcBundled = src.GetSchema();
if (srcBundled != null)
group.AddSchema(srcBundled, false);
var srcContent = src.GetSchema();
if (srcContent != null)
group.AddSchema(srcContent, false);
return group;
}
}