Files
zeling_v2/Assets/Scripts/Editor/AddressKeyValidator.cs
2026-05-08 11:04:00 +08:00

165 lines
6.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Settings;
#endif
namespace BaseGames.Editor
{
/// <summary>
/// Editor 工具:验证 <see cref="BaseGames.Core.Assets.AddressKeys"/> 中所有常量
/// 是否与 Addressable 分组中实际存在的地址同步(架构 13_AssetPoolModule §10
///
/// 菜单BaseGames → Tools → Validate Address Keys
/// </summary>
public static class AddressKeyValidator
{
[MenuItem("BaseGames/Tools/Validate Address Keys")]
public static void ValidateAll()
{
var results = RunValidation();
LogResults(results);
}
/// <summary>
/// 执行验证,返回每个 key 的验证结果。供 Build Pre-process 或测试调用。
/// </summary>
public static List<ValidationResult> RunValidation()
{
var results = new List<ValidationResult>();
var registeredAddresses = GetAllAddressableAddresses();
// 通过反射取出 AddressKeys 中所有 public const string 字段
var keyType = typeof(BaseGames.Core.Assets.AddressKeys);
var fields = keyType.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
.Where(f => f.IsLiteral && !f.IsInitOnly && f.FieldType == typeof(string));
foreach (var field in fields)
{
var value = (string)field.GetRawConstantValue();
var exists = registeredAddresses.Contains(value);
results.Add(new ValidationResult(field.Name, value, exists));
}
return results;
}
// ── Internal ──────────────────────────────────────────────────────────
private static HashSet<string> GetAllAddressableAddresses()
{
var addresses = new HashSet<string>(StringComparer.Ordinal);
#if UNITY_EDITOR
var settings = AddressableAssetSettingsDefaultObject.Settings;
if (settings == null)
{
Debug.LogWarning("[AddressKeyValidator] Addressable Settings 未找到,请先初始化 Addressables。");
return addresses;
}
foreach (var group in settings.groups)
{
if (group == null) continue;
foreach (var entry in group.entries)
{
if (entry != null)
addresses.Add(entry.address);
}
}
#endif
return addresses;
}
private static void LogResults(List<ValidationResult> results)
{
int missing = 0;
foreach (var r in results)
{
if (!r.ExistsInAddressables)
{
Debug.LogWarning($"[AddressKeyValidator] ⚠ 孤儿 KeyAddressKeys.{r.FieldName} = \"{r.Value}\" — 未在 Addressable 分组中找到对应地址。");
missing++;
}
}
if (missing == 0)
Debug.Log($"[AddressKeyValidator] ✓ 所有 {results.Count} 个 AddressKeys 常量均在 Addressable 分组中存在。");
else
Debug.LogWarning($"[AddressKeyValidator] 共 {results.Count} 个常量,发现 {missing} 个孤儿 Key请检查 Addressable 分组配置。");
}
// ── 结果结构 ──────────────────────────────────────────────────────────
public readonly struct ValidationResult
{
public readonly string FieldName;
public readonly string Value;
public readonly bool ExistsInAddressables;
public ValidationResult(string fieldName, string value, bool exists)
{
FieldName = fieldName;
Value = value;
ExistsInAddressables = exists;
}
}
}
/// <summary>
/// 资产导入后自动触发 AddressKey 验证(架构 13_AssetPoolModule §10
/// 仅在 Addressable Group 资产发生变更时触发,避免每次导入都验证。
/// </summary>
public class AddressKeyImportWatcher : AssetPostprocessor
{
private const string AddressableGroupAssetExt = ".asset";
private const string AddressableGroupFolder = "Assets/AddressableAssetsData";
private static void OnPostprocessAllAssets(
string[] importedAssets,
string[] deletedAssets,
string[] movedAssets,
string[] movedFromAssetPaths)
{
bool addressablesChanged = false;
foreach (var path in importedAssets)
{
if (path.StartsWith(AddressableGroupFolder, StringComparison.OrdinalIgnoreCase)
&& path.EndsWith(AddressableGroupAssetExt, StringComparison.OrdinalIgnoreCase))
{
addressablesChanged = true;
break;
}
}
if (!addressablesChanged)
{
foreach (var path in deletedAssets)
{
if (path.StartsWith(AddressableGroupFolder, StringComparison.OrdinalIgnoreCase))
{
addressablesChanged = true;
break;
}
}
}
if (addressablesChanged)
{
// 延迟一帧执行,等待 AssetDatabase 完全刷新
EditorApplication.delayCall += () =>
{
Debug.Log("[AddressKeyImportWatcher] 检测到 Addressable 分组变更,自动触发 Key 验证...");
AddressKeyValidator.ValidateAll();
};
}
}
}
}