using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
using UnityEngine;
namespace BaseGames.Editor
{
///
/// 可复用的 Addressable 注册器:把资产登记到正确的分组并按规范打标。
///
/// 分组与标签均由 推导(规范来源:
/// Docs/Standards/AddressablesLabelSpec.md §3 / AssetFolderSpec.md §8),
/// 因此结果与 AddressableManagerWindow、AddressKeyValidator 完全一致。
///
/// 供各脚手架(如 SceneObjectPlacerTool 创建 Prefab 后)一键注册,
/// 避免每个工具重复实现 Addressables Settings API。
///
public static class AddressableRegistrar
{
///
/// 将指定路径的资产注册为 Addressable。
/// 地址默认取文件名(可用 覆盖);
/// 分组与标签按 推导,
/// 在规范标签之上追加(如 E003 幼蛭额外的 Poolable/Preload)。
///
/// 最终写入的地址;Addressables 未初始化或资产不存在时返回 null。
public static string Register(string assetPath, string addressOverride = null,
IEnumerable extraLabels = null, List report = null)
{
var settings = AddressableAssetSettingsDefaultObject.Settings;
if (settings == null)
{
report?.Add("Addressable Asset Settings 不存在(未初始化),已跳过 Addressable 注册。");
return null;
}
string guid = AssetDatabase.AssetPathToGUID(assetPath);
if (string.IsNullOrEmpty(guid))
{
report?.Add($"资产不存在,无法注册 Addressable:{assetPath}");
return null;
}
string address = string.IsNullOrEmpty(addressOverride)
? System.IO.Path.GetFileNameWithoutExtension(assetPath)
: addressOverride;
string groupName = AddressableRules.GetExpectedGroup(address);
var group = groupName != null ? EnsureGroup(settings, groupName) : settings.DefaultGroup;
var entry = settings.FindAssetEntry(guid)
?? settings.CreateOrMoveEntry(guid, group, false, false);
if (entry == null)
{
report?.Add($"创建 Addressable 条目失败:{assetPath}");
return null;
}
entry.address = address;
settings.MoveEntry(entry, group, false, false);
var labels = new HashSet(AddressableRules.GetExpectedLabels(address));
if (extraLabels != null)
foreach (var l in extraLabels)
if (!string.IsNullOrWhiteSpace(l)) labels.Add(l);
foreach (var l in labels)
SetLabel(settings, entry, l);
settings.SetDirty(AddressableAssetSettings.ModificationEvent.EntryModified, entry, true);
report?.Add($"✅ Addressable 注册:{address} → 分组 {group.name}"
+ (labels.Count > 0 ? $",标签 [{string.Join(", ", labels.OrderBy(x => x))}]" : ",无标签"));
return address;
}
private static AddressableAssetGroup EnsureGroup(AddressableAssetSettings settings, string name)
{
var existing = settings.groups.FirstOrDefault(g => g != null && g.name == name);
if (existing != null) return existing;
var tmpl = settings.GroupTemplateObjects.FirstOrDefault() as AddressableAssetGroupTemplate;
var schemas = tmpl != null ? new List(tmpl.SchemaObjects) : null;
var created = settings.CreateGroup(name, false, false, true, schemas);
if (created != null)
Debug.Log($"[AddressableRegistrar] 已自动创建分组:{name}");
return created ?? settings.DefaultGroup;
}
private static void SetLabel(AddressableAssetSettings settings, AddressableAssetEntry entry, string label)
{
if (!settings.GetLabels().Contains(label))
{
settings.AddLabel(label, true);
Debug.Log($"[AddressableRegistrar] 已创建标签:{label}");
}
entry.SetLabel(label, true, true);
}
}
}