feat: Enhance Addressable tools with improved scanning and filtering features

- Updated AddressReferenceGraphWindow to scan for AddressKeys in the _Game directory and added a warning for missing directories.
- Enhanced AddressableBatchTool with new filters for asset types (Prefab, Scene, ScriptableObject, Texture, Audio) and improved UI layout for better usability.
- Introduced automatic application of grouping and labeling rules during registration in AddressableBatchTool.
- Added functionality to quickly scan the _Game folder and improved address building logic.
- Updated AddressableRuleSyncWindow to include handling for custom labels and improved reporting of issues.
- Enhanced AddressableRules with a whitelist for known labels and refined grouping and labeling logic based on asset prefixes.
This commit is contained in:
2026-05-22 13:34:47 +08:00
parent e7b44e1d60
commit f1c0b65737
4 changed files with 416 additions and 112 deletions

View File

@@ -36,11 +36,13 @@ namespace BaseGames.Editor
public string ExpectedGroup; // null = 规则未覆盖,维持现状
public string[] CurrentLabels;
public string[] ExpectedLabels;
public string[] MissingLabels; // 应有但没有
public string[] ExtraLabels; // 有但不应有
public bool GroupOk => ExpectedGroup == null || CurrentGroup == ExpectedGroup;
public bool LabelsOk => MissingLabels.Length == 0 && ExtraLabels.Length == 0;
public bool IsOk => GroupOk && LabelsOk;
public string[] MissingLabels; // 应有但没有(规则要求),红色错误
public string[] ExtraLabels; // 规则不要求且在 KnownLabels 中(多余规则标签),红色错误
public string[] UnknownLabels; // 规则不要求且不在 KnownLabels 中(自定义标签),黄色警告,不自动删除
public bool GroupOk => ExpectedGroup == null || CurrentGroup == ExpectedGroup;
public bool LabelsOk => MissingLabels.Length == 0 && ExtraLabels.Length == 0;
public bool IsOk => GroupOk && LabelsOk;
public bool HasWarnings => UnknownLabels.Length > 0;
}
// ── 状态 ──────────────────────────────────────────────────────────────
@@ -74,7 +76,7 @@ namespace BaseGames.Editor
public static void OpenWindow()
{
var win = GetWindow<AddressableRuleSyncWindow>("Addressable Rule Sync");
win.minSize = new Vector2(900, 520);
win.minSize = new Vector2(1040, 540);
win.Show();
}
@@ -108,6 +110,9 @@ namespace BaseGames.Editor
if (GUILayout.Button("扫描", EditorStyles.toolbarButton, GUILayout.Width(80)))
Scan();
if (GUILayout.Button("🔄 刷新", EditorStyles.toolbarButton, GUILayout.Width(60)))
Scan();
GUILayout.Space(8);
_showOk = GUILayout.Toggle(_showOk, "显示正常项", EditorStyles.toolbarButton, GUILayout.Width(80));
GUILayout.Space(8);
@@ -134,12 +139,14 @@ namespace BaseGames.Editor
{
if (!_scanned) return;
int total = _reports.Count;
int ok = _reports.Count(r => r.IsOk);
int issues = total - ok;
int total = _reports.Count;
int ok = _reports.Count(r => r.IsOk);
int issues = _reports.Count(r => !r.IsOk);
int warnings = _reports.Count(r => r.IsOk && r.HasWarnings);
int wrongGrp = _reports.Count(r => !r.GroupOk);
int misLabel = _reports.Count(r => r.MissingLabels.Length > 0);
int extLabel = _reports.Count(r => r.ExtraLabels.Length > 0);
int unkLabel = _reports.Count(r => r.UnknownLabels.Length > 0);
EditorGUILayout.Space(2);
using (new EditorGUILayout.HorizontalScope())
@@ -148,9 +155,11 @@ namespace BaseGames.Editor
GUILayout.Space(12);
DrawColoredLabel($"✅ 正常 {ok}", ColOk);
GUILayout.Space(12);
DrawColoredLabel($" 问题 {issues}", issues > 0 ? ColWarn : ColOk);
DrawColoredLabel($" 问题 {issues}", issues > 0 ? ColError : ColOk);
GUILayout.Space(8);
DrawColoredLabel($"⚠ 自定义标签 {unkLabel}", unkLabel > 0 ? ColWarn : ColOk);
GUILayout.Space(20);
GUILayout.Label($"分组错误 {wrongGrp} | 标签缺失 {misLabel} | 标签多余 {extLabel}",
GUILayout.Label($"分组错误 {wrongGrp} | 标签缺失 {misLabel} | 多余规则标签 {extLabel}",
EditorStyles.miniLabel);
GUILayout.FlexibleSpace();
}
@@ -164,12 +173,13 @@ namespace BaseGames.Editor
// 表头
using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar))
{
GUILayout.Label("Address", _boldStyle, GUILayout.Width(200));
GUILayout.Label("当前分组", _boldStyle, GUILayout.Width(130));
GUILayout.Label("期望分组", _boldStyle, GUILayout.Width(130));
GUILayout.Label("缺失标签", _boldStyle, GUILayout.Width(140));
GUILayout.Label("多余标签", _boldStyle, GUILayout.Width(120));
GUILayout.Label("状态", _boldStyle, GUILayout.Width(80));
GUILayout.Label("Address", _boldStyle, GUILayout.Width(200));
GUILayout.Label("当前分组", _boldStyle, GUILayout.Width(120));
GUILayout.Label("期望分组", _boldStyle, GUILayout.Width(120));
GUILayout.Label("缺失标签", _boldStyle, GUILayout.Width(130));
GUILayout.Label("多余规则标签", _boldStyle, GUILayout.Width(110));
GUILayout.Label("自定义标签", _boldStyle, GUILayout.Width(110));
GUILayout.Label("状态", _boldStyle, GUILayout.Width(80));
}
_scrollPos = EditorGUILayout.BeginScrollView(_scrollPos, GUILayout.ExpandHeight(true));
@@ -211,29 +221,35 @@ namespace BaseGames.Editor
// 当前分组
var grpColor = r.GroupOk ? ColOk : ColError;
DrawColoredLabel(r.CurrentGroup ?? "—", grpColor, GUILayout.Width(130));
DrawColoredLabel(r.CurrentGroup ?? "—", grpColor, GUILayout.Width(120));
// 期望分组
var expGrpText = r.ExpectedGroup ?? "(规则未覆盖)";
var expGrpText = r.ExpectedGroup ?? "(规则未覆盖)";
var expGrpColor = r.GroupOk ? ColOk : ColWarn;
DrawColoredLabel(expGrpText, expGrpColor, GUILayout.Width(130));
DrawColoredLabel(expGrpText, expGrpColor, GUILayout.Width(120));
// 缺失标签
// 缺失标签(红色,须补齐)
var missingText = r.MissingLabels.Length > 0 ? string.Join(", ", r.MissingLabels) : "—";
DrawColoredLabel(missingText, r.MissingLabels.Length > 0 ? ColError : ColOk, GUILayout.Width(140));
DrawColoredLabel(missingText, r.MissingLabels.Length > 0 ? ColError : ColOk, GUILayout.Width(130));
// 多余标签
// 多余规则标签(红色,将被 FixEntry 移除)
var extraText = r.ExtraLabels.Length > 0 ? string.Join(", ", r.ExtraLabels) : "—";
DrawColoredLabel(extraText, r.ExtraLabels.Length > 0 ? ColWarn : ColOk, GUILayout.Width(120));
DrawColoredLabel(extraText, r.ExtraLabels.Length > 0 ? ColError : ColOk, GUILayout.Width(110));
// 自定义标签(黄色警告,不会被自动删除,建议写入规范)
var unknownText = r.UnknownLabels.Length > 0 ? string.Join(", ", r.UnknownLabels) : "—";
DrawColoredLabel(unknownText, r.UnknownLabels.Length > 0 ? ColWarn : ColOk, GUILayout.Width(110));
// 状态 + 单条修复按钮
if (r.IsOk)
{
DrawColoredLabel("✅ 正常", ColOk, GUILayout.Width(80));
var statusColor = r.HasWarnings ? ColWarn : ColOk;
var statusText = r.HasWarnings ? "⚠ 自定义标签" : "✅ 正常";
DrawColoredLabel(statusText, statusColor, GUILayout.Width(80));
}
else
{
DrawColoredLabel(" 需修复", ColWarn, GUILayout.Width(60));
DrawColoredLabel(" 需修复", ColError, GUILayout.Width(60));
if (GUILayout.Button("修复", EditorStyles.miniButton, GUILayout.Width(40)))
FixEntry(r);
}
@@ -247,7 +263,8 @@ namespace BaseGames.Editor
EditorGUILayout.Space(4);
EditorGUILayout.HelpBox(
"规则来源Docs/Standards/AddressablesLabelSpec.md §3 分组规则AssetFolderSpec.md §8.1\n" +
"「修复所有问题」仅修改已注册资产的分组/标签,不注册新资产(请用 Addressable Batch Tool。",
"「修复所有问题」仅修改已注册资产的分组/标签,不注册新资产,不删除自定义标签(黄色警告项)。\n" +
"新增资产工作流:① Addressable Batch Tool → ⚡ 全量扫描 _Game/ → 注册所有 ② 返回此窗口 → 扫描 → 修复所有问题",
MessageType.None);
}
@@ -259,9 +276,6 @@ namespace BaseGames.Editor
var settings = AddressableAssetSettingsDefaultObject.Settings;
if (settings == null) return;
// 收集所有全局标签供"多余标签"判断
var allKnownLabels = new HashSet<string>(settings.GetLabels(), StringComparer.Ordinal);
foreach (var group in settings.groups)
{
if (group == null) continue;
@@ -275,32 +289,42 @@ namespace BaseGames.Editor
var currentLbls = entry.labels.ToArray();
var missing = expectedLbls.Except(currentLbls, StringComparer.Ordinal).ToArray();
var extra = currentLbls.Except(expectedLbls, StringComparer.Ordinal).ToArray();
// 区分两类"多余标签"
// extra = 规则已知标签KnownLabels中规则不要求的 → 红色FixEntry 会移除
// unknown = 不在 KnownLabels 中的自定义标签 → 黄色警告FixEntry 保留,建议写入规范
var notExpected = currentLbls.Except(expectedLbls, StringComparer.Ordinal);
var extra = notExpected.Where(l => AddressableRules.KnownLabels.Contains(l)).ToArray();
var unknown = notExpected.Where(l => !AddressableRules.KnownLabels.Contains(l)).ToArray();
_reports.Add(new EntryReport
{
Address = address,
AssetPath = entry.AssetPath,
CurrentGroup = group.name,
ExpectedGroup = expectedGroup,
CurrentLabels = currentLbls,
Address = address,
AssetPath = entry.AssetPath,
CurrentGroup = group.name,
ExpectedGroup = expectedGroup,
CurrentLabels = currentLbls,
ExpectedLabels = expectedLbls,
MissingLabels = missing,
ExtraLabels = extra,
MissingLabels = missing,
ExtraLabels = extra,
UnknownLabels = unknown,
});
}
}
// 问题项排前面,正常项排后;同类按 Address 字母序
// 问题项排前面,仅有警告的次之,正常项排后;同类按 Address 字母序
_reports = _reports
.OrderBy(r => r.IsOk)
.OrderBy(r => r.IsOk ? (r.HasWarnings ? 1 : 2) : 0)
.ThenBy(r => r.Address, StringComparer.Ordinal)
.ToList();
_scanned = true;
Repaint();
int issues = _reports.Count(r => !r.IsOk);
int warnings = _reports.Count(r => r.IsOk && r.HasWarnings);
Debug.Log($"[AddressableRuleSync] 扫描完成:{_reports.Count} 个条目," +
$"{_reports.Count(r => !r.IsOk)} 个需要修复。");
$"{issues} 个需要修复,{warnings} 个含自定义标签警告。");
}
// ── 修复逻辑 ──────────────────────────────────────────────────────────
@@ -310,6 +334,22 @@ namespace BaseGames.Editor
var issues = _reports.Where(r => !r.IsOk).ToList();
if (issues.Count == 0) return;
int moveCount = issues.Count(r => !r.GroupOk);
int addCount = issues.Sum(r => r.MissingLabels.Length);
int removeCount = issues.Sum(r => r.ExtraLabels.Length);
// 干跑预览对话框
bool confirmed = EditorUtility.DisplayDialog(
"确认修复所有问题",
$"将对 {issues.Count} 个条目执行以下操作:\n\n" +
$" • 移动分组:{moveCount} 个\n" +
$" • 添加标签:{addCount} 个\n" +
$" • 移除多余规则标签:{removeCount} 个\n\n" +
"⚠ 自定义标签(黄色警告项)不会被删除。\n" +
"此操作不可撤销,请确认后继续。",
"确认修复", "取消");
if (!confirmed) return;
int fixedCount = 0;
foreach (var r in issues)
{
@@ -355,7 +395,8 @@ namespace BaseGames.Editor
changed = true;
}
// 移除多余标签
// 移除多余规则标签ExtraLabels 只包含 KnownLabels 中规则不要求的标签;
// UnknownLabels 是用户自定义标签,刻意保留,不做删除)
foreach (var lbl in r.ExtraLabels)
{
entry.SetLabel(lbl, false, true);