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:
@@ -60,6 +60,11 @@ namespace BaseGames.Editor
|
||||
// Tab ③
|
||||
private List<SelectionEntry> _selectionEntries;
|
||||
private Vector2 _selectionScrollPos;
|
||||
private bool _selFilterPrefab = true;
|
||||
private bool _selFilterScene = true;
|
||||
private bool _selFilterSO = true;
|
||||
private bool _selFilterTexture;
|
||||
private bool _selFilterAudio;
|
||||
|
||||
// 共用
|
||||
private int _targetGroupIndex;
|
||||
@@ -67,6 +72,7 @@ namespace BaseGames.Editor
|
||||
private string _newGroupName = "New Group";
|
||||
private string _newLabel = "";
|
||||
private bool _overwriteAddress;
|
||||
private bool _applyRulesOnRegister = true;
|
||||
|
||||
// ── 样式(惰性初始化)────────────────────────────────────────────────
|
||||
private GUIStyle _headerStyle;
|
||||
@@ -81,7 +87,7 @@ namespace BaseGames.Editor
|
||||
public static void OpenWindow()
|
||||
{
|
||||
var win = GetWindow<AddressableBatchTool>(Title);
|
||||
win.minSize = new Vector2(600, 460);
|
||||
win.minSize = new Vector2(920, 520);
|
||||
win.Show();
|
||||
}
|
||||
|
||||
@@ -144,9 +150,11 @@ namespace BaseGames.Editor
|
||||
// 列表表头
|
||||
using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar))
|
||||
{
|
||||
EditorGUILayout.LabelField("常量名", _boldStyle, GUILayout.Width(200));
|
||||
EditorGUILayout.LabelField("地址 Key", _boldStyle, GUILayout.Width(180));
|
||||
EditorGUILayout.LabelField("状态", _boldStyle, GUILayout.Width(100));
|
||||
EditorGUILayout.LabelField("常量名", _boldStyle, GUILayout.Width(180));
|
||||
EditorGUILayout.LabelField("地址 Key", _boldStyle, GUILayout.Width(160));
|
||||
EditorGUILayout.LabelField("期望分组", _boldStyle, GUILayout.Width(110));
|
||||
EditorGUILayout.LabelField("期望标签", _boldStyle, GUILayout.Width(140));
|
||||
EditorGUILayout.LabelField("状态", _boldStyle, GUILayout.Width(80));
|
||||
EditorGUILayout.LabelField("匹配资产", _boldStyle);
|
||||
}
|
||||
|
||||
@@ -160,24 +168,30 @@ namespace BaseGames.Editor
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope(GUILayout.Height(20)))
|
||||
{
|
||||
EditorGUILayout.LabelField(entry.FieldName, GUILayout.Width(200));
|
||||
EditorGUILayout.LabelField(entry.AddressKey, GUILayout.Width(180));
|
||||
EditorGUILayout.LabelField(entry.FieldName, GUILayout.Width(180));
|
||||
EditorGUILayout.LabelField(entry.AddressKey, GUILayout.Width(160));
|
||||
EditorGUILayout.LabelField(
|
||||
AddressableRules.GetExpectedGroup(entry.AddressKey) ?? "Default",
|
||||
GUILayout.Width(110));
|
||||
EditorGUILayout.LabelField(
|
||||
FormatLabels(AddressableRules.GetExpectedLabels(entry.AddressKey)),
|
||||
GUILayout.Width(140));
|
||||
|
||||
if (entry.IsRegistered)
|
||||
{
|
||||
EditorGUILayout.LabelField("✅ 已注册", _okStyle, GUILayout.Width(100));
|
||||
EditorGUILayout.LabelField("✅ 已注册", _okStyle, GUILayout.Width(80));
|
||||
EditorGUILayout.LabelField(entry.ExistingAssetPath ?? "—");
|
||||
}
|
||||
else if (entry.FoundAssetPath != null)
|
||||
{
|
||||
EditorGUILayout.LabelField("⚠ 未注册", _warnStyle, GUILayout.Width(100));
|
||||
EditorGUILayout.LabelField("⚠ 未注册", _warnStyle, GUILayout.Width(80));
|
||||
EditorGUILayout.LabelField(entry.FoundAssetPath, GUILayout.ExpandWidth(true));
|
||||
if (GUILayout.Button("注册", GUILayout.Width(50)))
|
||||
RegisterKeyEntry(entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField("❌ 未找到", _warnStyle, GUILayout.Width(100));
|
||||
EditorGUILayout.LabelField("❌ 未找到", _warnStyle, GUILayout.Width(80));
|
||||
entry.ManualAsset = (UnityEngine.Object)EditorGUILayout.ObjectField(
|
||||
entry.ManualAsset, typeof(UnityEngine.Object), false);
|
||||
if (entry.ManualAsset != null)
|
||||
@@ -247,6 +261,8 @@ namespace BaseGames.Editor
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("⚡ 全量扫描 _Game/", GUILayout.Width(150)))
|
||||
QuickScanGameFolder();
|
||||
GUILayout.FlexibleSpace();
|
||||
GUI.enabled = !string.IsNullOrEmpty(_folderPath);
|
||||
if (GUILayout.Button("扫描文件夹", GUILayout.Width(100)))
|
||||
@@ -266,9 +282,14 @@ namespace BaseGames.Editor
|
||||
EditorGUILayout.Space(4);
|
||||
using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar))
|
||||
{
|
||||
EditorGUILayout.LabelField("资产路径", _boldStyle, GUILayout.ExpandWidth(true));
|
||||
EditorGUILayout.LabelField("预计地址", _boldStyle, GUILayout.Width(200));
|
||||
EditorGUILayout.LabelField("状态", _boldStyle, GUILayout.Width(80));
|
||||
EditorGUILayout.LabelField("资产路径", _boldStyle, GUILayout.Width(180));
|
||||
EditorGUILayout.LabelField("地址", _boldStyle, GUILayout.Width(150));
|
||||
if (_applyRulesOnRegister)
|
||||
{
|
||||
EditorGUILayout.LabelField("分组(规则)", _boldStyle, GUILayout.Width(120));
|
||||
EditorGUILayout.LabelField("标签(规则)", _boldStyle, GUILayout.Width(150));
|
||||
}
|
||||
EditorGUILayout.LabelField("状态", _boldStyle, GUILayout.Width(70));
|
||||
}
|
||||
|
||||
_folderScrollPos = EditorGUILayout.BeginScrollView(_folderScrollPos, GUILayout.ExpandHeight(true));
|
||||
@@ -276,11 +297,16 @@ namespace BaseGames.Editor
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope(GUILayout.Height(18)))
|
||||
{
|
||||
EditorGUILayout.LabelField(entry.AssetPath, GUILayout.ExpandWidth(true));
|
||||
entry.Address = EditorGUILayout.TextField(entry.Address, GUILayout.Width(200));
|
||||
EditorGUILayout.LabelField(entry.AssetPath, GUILayout.Width(180));
|
||||
entry.Address = EditorGUILayout.TextField(entry.Address, GUILayout.Width(150));
|
||||
if (_applyRulesOnRegister)
|
||||
{
|
||||
EditorGUILayout.LabelField(entry.PredictedGroup ?? "Default", GUILayout.Width(120));
|
||||
EditorGUILayout.LabelField(entry.PredictedLabels ?? "—", GUILayout.Width(150));
|
||||
}
|
||||
var label = entry.AlreadyRegistered ? "✅ 已有" : "待注册";
|
||||
var style = entry.AlreadyRegistered ? _okStyle : EditorStyles.miniLabel;
|
||||
EditorGUILayout.LabelField(label, style, GUILayout.Width(80));
|
||||
EditorGUILayout.LabelField(label, style, GUILayout.Width(70));
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndScrollView();
|
||||
@@ -296,6 +322,18 @@ namespace BaseGames.Editor
|
||||
EditorGUILayout.LabelField("在 Project 窗口中选中资产或文件夹,然后点击「读取选中项」。", EditorStyles.wordWrappedMiniLabel);
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
// 资产类型筛选(与 Tab ② 一致,防止误注册不该 Addressable 的文件类型)
|
||||
EditorGUILayout.LabelField("资产类型筛选", EditorStyles.boldLabel);
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
_selFilterPrefab = GUILayout.Toggle(_selFilterPrefab, "Prefab", GUILayout.Width(70));
|
||||
_selFilterScene = GUILayout.Toggle(_selFilterScene, "Scene", GUILayout.Width(70));
|
||||
_selFilterSO = GUILayout.Toggle(_selFilterSO, "SO/Asset", GUILayout.Width(80));
|
||||
_selFilterTexture = GUILayout.Toggle(_selFilterTexture, "Texture", GUILayout.Width(70));
|
||||
_selFilterAudio = GUILayout.Toggle(_selFilterAudio, "Audio", GUILayout.Width(70));
|
||||
}
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
@@ -316,9 +354,14 @@ namespace BaseGames.Editor
|
||||
EditorGUILayout.Space(4);
|
||||
using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar))
|
||||
{
|
||||
EditorGUILayout.LabelField("资产路径", _boldStyle, GUILayout.ExpandWidth(true));
|
||||
EditorGUILayout.LabelField("注册地址", _boldStyle, GUILayout.Width(200));
|
||||
EditorGUILayout.LabelField("状态", _boldStyle, GUILayout.Width(80));
|
||||
EditorGUILayout.LabelField("资产路径", _boldStyle, GUILayout.Width(180));
|
||||
EditorGUILayout.LabelField("注册地址", _boldStyle, GUILayout.Width(150));
|
||||
if (_applyRulesOnRegister)
|
||||
{
|
||||
EditorGUILayout.LabelField("分组(规则)", _boldStyle, GUILayout.Width(120));
|
||||
EditorGUILayout.LabelField("标签(规则)", _boldStyle, GUILayout.Width(150));
|
||||
}
|
||||
EditorGUILayout.LabelField("状态", _boldStyle, GUILayout.Width(70));
|
||||
}
|
||||
|
||||
_selectionScrollPos = EditorGUILayout.BeginScrollView(_selectionScrollPos, GUILayout.ExpandHeight(true));
|
||||
@@ -326,11 +369,16 @@ namespace BaseGames.Editor
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope(GUILayout.Height(18)))
|
||||
{
|
||||
EditorGUILayout.LabelField(entry.AssetPath, GUILayout.ExpandWidth(true));
|
||||
entry.Address = EditorGUILayout.TextField(entry.Address, GUILayout.Width(200));
|
||||
EditorGUILayout.LabelField(entry.AssetPath, GUILayout.Width(180));
|
||||
entry.Address = EditorGUILayout.TextField(entry.Address, GUILayout.Width(150));
|
||||
if (_applyRulesOnRegister)
|
||||
{
|
||||
EditorGUILayout.LabelField(entry.PredictedGroup ?? "Default", GUILayout.Width(120));
|
||||
EditorGUILayout.LabelField(entry.PredictedLabels ?? "—", GUILayout.Width(150));
|
||||
}
|
||||
var label = entry.AlreadyRegistered ? "✅ 已有" : "待注册";
|
||||
var style = entry.AlreadyRegistered ? _okStyle : EditorStyles.miniLabel;
|
||||
EditorGUILayout.LabelField(label, style, GUILayout.Width(80));
|
||||
EditorGUILayout.LabelField(label, style, GUILayout.Width(70));
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndScrollView();
|
||||
@@ -347,22 +395,32 @@ namespace BaseGames.Editor
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
EditorGUILayout.LabelField("目标分组", GUILayout.Width(70));
|
||||
if (_groupNames != null && _groupNames.Length > 0)
|
||||
// 自动规则模式下,目标分组由规则决定,手动选择无效
|
||||
GUI.enabled = !_applyRulesOnRegister;
|
||||
if (_applyRulesOnRegister)
|
||||
{
|
||||
EditorGUILayout.LabelField("(由 AddressableRules 自动决定)",
|
||||
EditorStyles.miniLabel, GUILayout.Width(200));
|
||||
}
|
||||
else if (_groupNames != null && _groupNames.Length > 0)
|
||||
{
|
||||
_targetGroupIndex = EditorGUILayout.Popup(_targetGroupIndex,
|
||||
_groupNames, GUILayout.Width(200));
|
||||
}
|
||||
GUI.enabled = true;
|
||||
|
||||
EditorGUILayout.Space(8);
|
||||
EditorGUILayout.LabelField("标签", GUILayout.Width(30));
|
||||
EditorGUILayout.LabelField("附加标签", GUILayout.Width(52));
|
||||
_newLabel = EditorGUILayout.TextField(_newLabel, GUILayout.Width(120));
|
||||
GUILayout.Label("(留空则不添加标签)", EditorStyles.miniLabel);
|
||||
GUILayout.Label("(可在规则标签基础上追加)", EditorStyles.miniLabel);
|
||||
GUILayout.FlexibleSpace();
|
||||
}
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
_overwriteAddress = GUILayout.Toggle(_overwriteAddress, "已注册的资产也覆盖地址");
|
||||
_overwriteAddress = GUILayout.Toggle(_overwriteAddress, "已注册的资产也覆盖地址");
|
||||
GUILayout.Space(16);
|
||||
_applyRulesOnRegister = GUILayout.Toggle(_applyRulesOnRegister, "自动应用分组/标签规则");
|
||||
GUILayout.FlexibleSpace();
|
||||
if (GUILayout.Button("新建分组…", GUILayout.Width(100)))
|
||||
ShowCreateGroupDialog();
|
||||
@@ -469,7 +527,7 @@ namespace BaseGames.Editor
|
||||
_folderEntries = new List<FolderEntry>();
|
||||
if (!AssetDatabase.IsValidFolder(_folderPath)) return;
|
||||
|
||||
var settings = AddressableAssetSettingsDefaultObject.Settings;
|
||||
var settings = AddressableAssetSettingsDefaultObject.Settings;
|
||||
var registeredGuids = CollectRegisteredGuids(settings);
|
||||
|
||||
var filters = BuildSearchFilter();
|
||||
@@ -479,23 +537,45 @@ namespace BaseGames.Editor
|
||||
|
||||
string absFolder = Path.GetFullPath(_folderPath);
|
||||
|
||||
// 收集所有文件
|
||||
var allFiles = new List<string>();
|
||||
foreach (string filter in filters)
|
||||
allFiles.AddRange(Directory.GetFiles(absFolder, filter, option));
|
||||
|
||||
try
|
||||
{
|
||||
foreach (string absPath in Directory.GetFiles(absFolder, filter, option))
|
||||
for (int i = 0; i < allFiles.Count; i++)
|
||||
{
|
||||
string absPath = allFiles[i];
|
||||
|
||||
if (i % 20 == 0)
|
||||
EditorUtility.DisplayProgressBar("扫描文件夹",
|
||||
Path.GetFileName(absPath),
|
||||
(float)i / allFiles.Count);
|
||||
|
||||
string relPath = "Assets" + absPath.Substring(Application.dataPath.Length).Replace('\\', '/');
|
||||
string guid = AssetDatabase.AssetPathToGUID(relPath);
|
||||
if (!IsAddressableAssetPath(relPath)) continue;
|
||||
if (ShouldExclude(relPath)) continue;
|
||||
|
||||
string guid = AssetDatabase.AssetPathToGUID(relPath);
|
||||
if (string.IsNullOrEmpty(guid)) continue;
|
||||
|
||||
string addr = BuildAddress(relPath);
|
||||
_folderEntries.Add(new FolderEntry
|
||||
{
|
||||
AssetPath = relPath,
|
||||
Guid = guid,
|
||||
Address = BuildAddress(relPath),
|
||||
Address = addr,
|
||||
AlreadyRegistered = registeredGuids.Contains(guid),
|
||||
PredictedGroup = AddressableRules.GetExpectedGroup(addr),
|
||||
PredictedLabels = FormatLabels(AddressableRules.GetExpectedLabels(addr)),
|
||||
});
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
|
||||
// 去重(多个 filter 可能匹配同一文件)
|
||||
_folderEntries = _folderEntries
|
||||
@@ -504,6 +584,34 @@ namespace BaseGames.Editor
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回 true 表示该文件应从 Addressable 注册中排除。
|
||||
/// 规范来源:AddressablesLabelSpec §5.2(禁止注册项)。
|
||||
/// </summary>
|
||||
private static bool ShouldExclude(string relPath)
|
||||
{
|
||||
string lowerPath = relPath.Replace('\\', '/').ToLowerInvariant();
|
||||
string fileName = Path.GetFileNameWithoutExtension(relPath);
|
||||
|
||||
// 测试场景(放在 Scenes/Testings/ 下)
|
||||
if (lowerPath.Contains("/scenes/testings/")) return true;
|
||||
|
||||
// 事件频道 ScriptableObject(EVT_ 前缀)
|
||||
if (fileName.StartsWith("EVT_", StringComparison.Ordinal)) return true;
|
||||
|
||||
// Sprite Atlas — 随依赖它的 Prefab 隐式打包,不单独注册
|
||||
if (Path.GetExtension(relPath) == ".spriteatlas") return true;
|
||||
|
||||
// Material — 随 Prefab 依赖关系打包,不单独注册
|
||||
if (Path.GetExtension(relPath) == ".mat") return true;
|
||||
|
||||
// HitBox / HurtBox 等碰撞盒子 Prefab(子 Prefab,不独立寻址)
|
||||
if (fileName.StartsWith("HitBox_", StringComparison.OrdinalIgnoreCase)) return true;
|
||||
if (fileName.StartsWith("HurtBox_", StringComparison.OrdinalIgnoreCase)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void RegisterAllFolderEntries()
|
||||
{
|
||||
int count = 0;
|
||||
@@ -554,12 +662,29 @@ namespace BaseGames.Editor
|
||||
|
||||
private void AddSelectionEntry(string guid, string path, HashSet<string> registeredGuids)
|
||||
{
|
||||
if (!IsAddressableAssetPath(path)) return;
|
||||
if (ShouldExclude(path)) return;
|
||||
|
||||
// 资产类型筛选(与 Tab ③ 筛选 Toggle 联动)
|
||||
string ext = Path.GetExtension(path).ToLowerInvariant();
|
||||
bool isMatch = (_selFilterPrefab && ext == ".prefab")
|
||||
|| (_selFilterScene && ext == ".unity")
|
||||
|| (_selFilterSO && ext == ".asset")
|
||||
|| (_selFilterTexture && (ext == ".png" || ext == ".jpg" || ext == ".tga"))
|
||||
|| (_selFilterAudio && (ext == ".mp3" || ext == ".wav" || ext == ".ogg"));
|
||||
// 若没有任何类型 Toggle 被勾选,则接受所有类型(兜底行为,避免全部筛空)
|
||||
bool anyToggled = _selFilterPrefab || _selFilterScene || _selFilterSO || _selFilterTexture || _selFilterAudio;
|
||||
if (anyToggled && !isMatch) return;
|
||||
|
||||
string addr = BuildAddress(path);
|
||||
_selectionEntries.Add(new SelectionEntry
|
||||
{
|
||||
AssetPath = path,
|
||||
Guid = guid,
|
||||
Address = BuildAddress(path),
|
||||
Address = addr,
|
||||
AlreadyRegistered = registeredGuids.Contains(guid),
|
||||
PredictedGroup = AddressableRules.GetExpectedGroup(addr),
|
||||
PredictedLabels = FormatLabels(AddressableRules.GetExpectedLabels(addr)),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -584,8 +709,24 @@ namespace BaseGames.Editor
|
||||
if (string.IsNullOrEmpty(guid)) return;
|
||||
|
||||
var settings = AddressableAssetSettingsDefaultObject.Settings;
|
||||
var group = groupNameOverride != null
|
||||
? GetOrCreateGroup(settings, groupNameOverride)
|
||||
|
||||
// 重复地址检查:同一 address 已注册到不同 GUID 时提示确认
|
||||
var existingByAddress = FindEntryByAddress(settings, address);
|
||||
if (existingByAddress != null && existingByAddress.guid != guid)
|
||||
{
|
||||
bool proceed = EditorUtility.DisplayDialog(
|
||||
"⚠ 地址已存在",
|
||||
$"地址 \"{address}\" 已注册到:\n{existingByAddress.AssetPath}\n\n" +
|
||||
$"继续会将该地址重新指向当前资产(GUID: {guid})。是否继续?",
|
||||
"继续", "取消");
|
||||
if (!proceed) return;
|
||||
}
|
||||
|
||||
// Determine target group: explicit override → rules → manual selection
|
||||
string effectiveGroup = groupNameOverride
|
||||
?? (_applyRulesOnRegister ? AddressableRules.GetExpectedGroup(address) : null);
|
||||
var group = effectiveGroup != null
|
||||
? GetOrCreateGroup(settings, effectiveGroup)
|
||||
: GetTargetGroup(settings);
|
||||
if (group == null) return;
|
||||
|
||||
@@ -601,6 +742,28 @@ namespace BaseGames.Editor
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_newLabel))
|
||||
entry.SetLabel(_newLabel.Trim(), true, true);
|
||||
|
||||
// Apply rules-based labels
|
||||
if (_applyRulesOnRegister)
|
||||
{
|
||||
foreach (var lbl in AddressableRules.GetExpectedLabels(address))
|
||||
{
|
||||
EnsureLabelExists(settings, lbl);
|
||||
entry.SetLabel(lbl, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static AddressableAssetEntry FindEntryByAddress(AddressableAssetSettings settings, string address)
|
||||
{
|
||||
if (settings == null) return null;
|
||||
foreach (var group in settings.groups)
|
||||
{
|
||||
if (group == null) continue;
|
||||
foreach (var e in group.entries)
|
||||
if (e != null && e.address == address) return e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private AddressableAssetGroup GetOrCreateGroup(AddressableAssetSettings settings, string groupName)
|
||||
@@ -636,8 +799,36 @@ namespace BaseGames.Editor
|
||||
AddressableAssetSettings.ModificationEvent.EntryModified, null, true);
|
||||
}
|
||||
|
||||
private static void EnsureLabelExists(AddressableAssetSettings settings, string label)
|
||||
{
|
||||
if (!settings.GetLabels().Contains(label))
|
||||
{
|
||||
settings.AddLabel(label, true);
|
||||
Debug.Log($"[AddressableBatch] 已创建标签:{label}");
|
||||
}
|
||||
}
|
||||
|
||||
private static string FormatLabels(string[] labels)
|
||||
=> labels.Length > 0 ? string.Join(", ", labels) : "—";
|
||||
|
||||
// ══ 创建分组 ══════════════════════════════════════════════════════════
|
||||
|
||||
private void QuickScanGameFolder()
|
||||
{
|
||||
_folderPath = "Assets/_Game";
|
||||
_folderAsset = AssetDatabase.LoadAssetAtPath<DefaultAsset>(_folderPath);
|
||||
_includeSubfolders = true;
|
||||
_filterPrefab = true;
|
||||
_filterScene = true;
|
||||
_filterSO = true;
|
||||
_filterAudio = true;
|
||||
_filterTexture = false;
|
||||
_addressFormat = AddressFormat.FileName;
|
||||
_applyRulesOnRegister = true;
|
||||
_tab = 1;
|
||||
ScanFolder();
|
||||
}
|
||||
|
||||
private void ShowCreateGroupDialog()
|
||||
{
|
||||
_newGroupName = EditorInputDialog.Show("新建 Addressable 分组", "请输入分组名称:", _newGroupName);
|
||||
@@ -684,15 +875,29 @@ namespace BaseGames.Editor
|
||||
|
||||
private string BuildAddress(string assetPath)
|
||||
{
|
||||
string fileName = Path.GetFileNameWithoutExtension(assetPath);
|
||||
string fileName = Path.GetFileNameWithoutExtension(assetPath);
|
||||
string relativePath = MakeRelativePath(assetPath, _folderPath);
|
||||
|
||||
return _addressFormat switch
|
||||
{
|
||||
AddressFormat.FileName => fileName,
|
||||
AddressFormat.FullAssetPath => assetPath,
|
||||
AddressFormat.RelativeToFolder => MakeRelativePath(assetPath, _folderPath),
|
||||
AddressFormat.PrefixPlusFileName => _addressPrefix + fileName,
|
||||
AddressFormat.PrefixPlusRelativePath=> _addressPrefix + MakeRelativePath(assetPath, _folderPath),
|
||||
_ => fileName,
|
||||
AddressFormat.FileName => fileName,
|
||||
AddressFormat.FullAssetPath => assetPath,
|
||||
AddressFormat.RelativeToFolder => relativePath,
|
||||
// 前缀拼接:前缀以 '/' 结尾时直接连接(如 "Config/" + "FootstepCatalog")
|
||||
// 前缀不以 '/' 结尾时用 '_' 连接(如 "Room_Forest" + "_01")
|
||||
AddressFormat.PrefixPlusFileName =>
|
||||
string.IsNullOrEmpty(_addressPrefix)
|
||||
? fileName
|
||||
: (_addressPrefix.EndsWith("/")
|
||||
? _addressPrefix + fileName
|
||||
: _addressPrefix + "_" + fileName),
|
||||
AddressFormat.PrefixPlusRelativePath =>
|
||||
string.IsNullOrEmpty(_addressPrefix)
|
||||
? relativePath
|
||||
: (_addressPrefix.EndsWith("/")
|
||||
? _addressPrefix + relativePath
|
||||
: _addressPrefix + "_" + relativePath),
|
||||
_ => fileName,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -716,6 +921,29 @@ namespace BaseGames.Editor
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断路径是否为可寻址资产(排除脚本、程序集定义、Shader、Sprite Atlas、Material 等文件)。
|
||||
/// </summary>
|
||||
private static bool IsAddressableAssetPath(string path)
|
||||
{
|
||||
string ext = Path.GetExtension(path);
|
||||
if (string.IsNullOrEmpty(ext)) return false;
|
||||
// 排除代码 / 元数据类文件
|
||||
return ext != ".cs"
|
||||
&& ext != ".asmdef"
|
||||
&& ext != ".asmref"
|
||||
&& ext != ".shader"
|
||||
&& ext != ".hlsl"
|
||||
&& ext != ".cginc"
|
||||
&& ext != ".glsl"
|
||||
&& ext != ".json"
|
||||
&& ext != ".xml"
|
||||
&& ext != ".txt"
|
||||
&& ext != ".md"
|
||||
&& ext != ".spriteatlas" // 随依赖它的 Prefab 隐式打包
|
||||
&& ext != ".mat"; // Material 随 Prefab 依赖打包
|
||||
}
|
||||
|
||||
/// <summary>从 AddressKey(如 "ENM_GruntWarrior")派生搜索名("GruntWarrior")。</summary>
|
||||
private static string DeriveName(string key)
|
||||
{
|
||||
@@ -740,27 +968,6 @@ namespace BaseGames.Editor
|
||||
return string.Equals(name, searchName, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断路径是否为可寻址资产(排除脚本、程序集定义、Shader 等代码文件)。
|
||||
/// </summary>
|
||||
private static bool IsAddressableAssetPath(string path)
|
||||
{
|
||||
string ext = Path.GetExtension(path);
|
||||
if (string.IsNullOrEmpty(ext)) return false;
|
||||
// 排除代码 / 元数据类文件
|
||||
return ext != ".cs"
|
||||
&& ext != ".asmdef"
|
||||
&& ext != ".asmref"
|
||||
&& ext != ".shader"
|
||||
&& ext != ".hlsl"
|
||||
&& ext != ".cginc"
|
||||
&& ext != ".glsl"
|
||||
&& ext != ".json"
|
||||
&& ext != ".xml"
|
||||
&& ext != ".txt"
|
||||
&& ext != ".md";
|
||||
}
|
||||
|
||||
private void InitStyles()
|
||||
{
|
||||
if (_stylesInitialized) return;
|
||||
@@ -790,6 +997,8 @@ namespace BaseGames.Editor
|
||||
public string Guid;
|
||||
public string Address;
|
||||
public bool AlreadyRegistered;
|
||||
public string PredictedGroup;
|
||||
public string PredictedLabels;
|
||||
}
|
||||
|
||||
private class SelectionEntry
|
||||
@@ -798,6 +1007,8 @@ namespace BaseGames.Editor
|
||||
public string Guid;
|
||||
public string Address;
|
||||
public bool AlreadyRegistered;
|
||||
public string PredictedGroup;
|
||||
public string PredictedLabels;
|
||||
}
|
||||
|
||||
private enum AddressFormat
|
||||
|
||||
Reference in New Issue
Block a user