diff --git a/Assets/YooAsset/Editor/BundleCollector/AssetSearch.meta b/Assets/YooAsset/Editor/BundleCollector/AssetSearch.meta
new file mode 100644
index 00000000..7e2cc0fd
--- /dev/null
+++ b/Assets/YooAsset/Editor/BundleCollector/AssetSearch.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 07c436f0dfa2bcf43b12628aed2aa91c
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/BundleCollector/AssetSearch/CollectAssetSearchResult.cs b/Assets/YooAsset/Editor/BundleCollector/AssetSearch/CollectAssetSearchResult.cs
new file mode 100644
index 00000000..e8ba1ca8
--- /dev/null
+++ b/Assets/YooAsset/Editor/BundleCollector/AssetSearch/CollectAssetSearchResult.cs
@@ -0,0 +1,52 @@
+
+namespace YooAsset.Editor
+{
+ ///
+ /// 收集资源搜索结果
+ ///
+ public class CollectAssetSearchResult
+ {
+ ///
+ /// 命中的收集器分组
+ ///
+ public BundleCollectorGroup Group { get; }
+
+ ///
+ /// 命中的收集器分组索引
+ ///
+ public int GroupIndex { get; }
+
+ ///
+ /// 命中的收集器
+ ///
+ public BundleCollector Collector { get; }
+
+ ///
+ /// 命中的收集器索引
+ ///
+ public int CollectorIndex { get; }
+
+ ///
+ /// 命中的资源路径
+ ///
+ public string AssetPath { get; }
+
+ ///
+ /// 构建收集资源搜索结果
+ ///
+ /// 命中的收集器分组
+ /// 命中的收集器分组索引
+ /// 命中的收集器
+ /// 命中的收集器索引
+ /// 命中的资源路径
+ public CollectAssetSearchResult(BundleCollectorGroup group, int groupIndex,
+ BundleCollector collector, int collectorIndex, string assetPath)
+ {
+ Group = group;
+ GroupIndex = groupIndex;
+ Collector = collector;
+ CollectorIndex = collectorIndex;
+ AssetPath = assetPath;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/BundleCollector/AssetSearch/CollectAssetSearchResult.cs.meta b/Assets/YooAsset/Editor/BundleCollector/AssetSearch/CollectAssetSearchResult.cs.meta
new file mode 100644
index 00000000..4493f21f
--- /dev/null
+++ b/Assets/YooAsset/Editor/BundleCollector/AssetSearch/CollectAssetSearchResult.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ff1a09e6aca8b104c9b256885b06130f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/BundleCollector/AssetSearch/CollectAssetSearchUtility.cs b/Assets/YooAsset/Editor/BundleCollector/AssetSearch/CollectAssetSearchUtility.cs
new file mode 100644
index 00000000..0e9f3659
--- /dev/null
+++ b/Assets/YooAsset/Editor/BundleCollector/AssetSearch/CollectAssetSearchUtility.cs
@@ -0,0 +1,148 @@
+using System;
+using UnityEngine;
+using UnityEditor;
+
+namespace YooAsset.Editor
+{
+ ///
+ /// 收集资源搜索工具类
+ ///
+ public static class CollectAssetSearchUtility
+ {
+ ///
+ /// 验证搜索路径
+ ///
+ /// 搜索路径
+ /// 搜索路径错误类型
+ public static ECollectAssetSearchError ValidateSearchPath(string input)
+ {
+ if (string.IsNullOrEmpty(input))
+ return ECollectAssetSearchError.InputPathEmpty;
+
+ if (input.StartsWith("Assets/", StringComparison.OrdinalIgnoreCase) == false)
+ return ECollectAssetSearchError.InputPathMissingAssetsPrefix;
+
+ if (input.EndsWith("/"))
+ return ECollectAssetSearchError.InputPathEndsWithSlash;
+
+ string fileName = System.IO.Path.GetFileName(input);
+ if (fileName.Contains(".") == false)
+ return ECollectAssetSearchError.InputPathMissingExtension;
+
+ if (AssetDatabase.IsValidFolder(input))
+ return ECollectAssetSearchError.InputPathIsFolder;
+
+ string guid = AssetDatabase.AssetPathToGUID(input);
+ if (string.IsNullOrEmpty(guid))
+ return ECollectAssetSearchError.AssetPathNotExists;
+
+ return ECollectAssetSearchError.None;
+ }
+
+ ///
+ /// 获取搜索路径错误提示信息
+ ///
+ /// 搜索路径错误类型
+ /// 搜索路径
+ /// 错误提示信息
+ public static string GetSearchPathErrorMessage(ECollectAssetSearchError error, string input)
+ {
+ switch (error)
+ {
+ case ECollectAssetSearchError.InputPathEmpty:
+ return "Please enter an asset path.";
+ case ECollectAssetSearchError.InputPathMissingAssetsPrefix:
+ return "Path must start with Assets/.";
+ case ECollectAssetSearchError.InputPathEndsWithSlash:
+ return "Please enter a file path. Do not end with /.";
+ case ECollectAssetSearchError.InputPathMissingExtension:
+ return "Path is missing a file extension (e.g. .prefab, .png, .mat).";
+ case ECollectAssetSearchError.InputPathIsFolder:
+ return "Please enter an asset file path, not a folder path.";
+ case ECollectAssetSearchError.AssetPathNotExists:
+ return $"Asset not found: {input}";
+ default:
+ return "Invalid input format.";
+ }
+ }
+
+ ///
+ /// 在指定 Package 中搜索资源路径,找到第一个命中结果即返回
+ ///
+ /// 搜索的资源包裹
+ /// 资源路径
+ /// 搜索结果,如果未找到返回 null
+ public static CollectAssetSearchResult SearchAssetPath(BundleCollectorPackage package, string assetPath)
+ {
+ if (ValidateSearchPath(assetPath) != ECollectAssetSearchError.None)
+ return null;
+
+ IAssetIgnoreRule ignoreRule = BundleCollectorSettingData.GetAssetIgnoreRuleInstance(package.IgnoreRuleName);
+ var command = new CollectCommand(package.PackageName, ignoreRule);
+ command.SetFlag(ECollectFlags.IgnoreGetDependencies, true);
+ command.UniqueBundleName = BundleCollectorSettingData.Setting.UniqueBundleName;
+ command.EnableAddressable = package.EnableAddressable;
+ command.SupportExtensionless = package.SupportExtensionless;
+ command.LocationToLower = package.LocationToLower;
+ command.IncludeAssetGUID = package.IncludeAssetGUID;
+ command.AutoCollectShaders = package.AutoCollectShaders;
+
+ for (int groupIndex = 0; groupIndex < package.Groups.Count; groupIndex++)
+ {
+ var group = package.Groups[groupIndex];
+ for (int collectIndex = 0; collectIndex < group.Collectors.Count; collectIndex++)
+ {
+ var collector = group.Collectors[collectIndex];
+
+ // 判断收集器是否可能收集指定资源
+ if (IsCandidateCollector(collector, assetPath) == false)
+ continue;
+
+ try
+ {
+ // 检测配置是否有效
+ collector.CheckConfigError();
+
+ // 收集有效资源信息
+ var collectAssets = collector.GetAllCollectAssets(command, group);
+ foreach (var collectAsset in collectAssets)
+ {
+ if (string.Equals(collectAsset.AssetInfo.AssetPath, assetPath, StringComparison.OrdinalIgnoreCase))
+ {
+ return new CollectAssetSearchResult(group, groupIndex, collector, collectIndex, assetPath);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Debug.LogError($"Invalid collector : {collector.CollectPath}, error: {e.Message}");
+ }
+ }
+ }
+
+ // 未找到匹配资源
+ return null;
+ }
+
+ ///
+ /// 判断收集器是否可能收集指定资源
+ ///
+ /// 收集器
+ /// 资源路径
+ /// 如果收集器可能收集该资源返回 true
+ private static bool IsCandidateCollector(BundleCollector collector, string assetPath)
+ {
+ if (string.IsNullOrEmpty(collector.CollectPath))
+ return false;
+
+ if (AssetDatabase.IsValidFolder(collector.CollectPath))
+ {
+ string folderPath = collector.CollectPath.TrimEnd('/') + "/";
+ return assetPath.StartsWith(folderPath, StringComparison.OrdinalIgnoreCase);
+ }
+
+ // 注意:资源收集器也可能直接配置的单个资源路径
+ return string.Equals(assetPath, collector.CollectPath, StringComparison.OrdinalIgnoreCase);
+ }
+ }
+}
diff --git a/Assets/YooAsset/Editor/BundleCollector/AssetSearch/CollectAssetSearchUtility.cs.meta b/Assets/YooAsset/Editor/BundleCollector/AssetSearch/CollectAssetSearchUtility.cs.meta
new file mode 100644
index 00000000..cabfdaee
--- /dev/null
+++ b/Assets/YooAsset/Editor/BundleCollector/AssetSearch/CollectAssetSearchUtility.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6c8bc2931bda7884198893f1d2e8f364
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/BundleCollector/AssetSearch/ECollectAssetSearchError.cs b/Assets/YooAsset/Editor/BundleCollector/AssetSearch/ECollectAssetSearchError.cs
new file mode 100644
index 00000000..e3d627f4
--- /dev/null
+++ b/Assets/YooAsset/Editor/BundleCollector/AssetSearch/ECollectAssetSearchError.cs
@@ -0,0 +1,44 @@
+
+namespace YooAsset.Editor
+{
+ ///
+ /// 搜索错误类型
+ ///
+ public enum ECollectAssetSearchError
+ {
+ ///
+ /// 无错误
+ ///
+ None,
+
+ ///
+ /// 输入路径为空
+ ///
+ InputPathEmpty,
+
+ ///
+ /// 输入路径缺少 Assets/ 路径前缀
+ ///
+ InputPathMissingAssetsPrefix,
+
+ ///
+ /// 输入路径以斜杠结尾
+ ///
+ InputPathEndsWithSlash,
+
+ ///
+ /// 输入路径缺少文件扩展名
+ ///
+ InputPathMissingExtension,
+
+ ///
+ /// 输入路径的是文件夹路径
+ ///
+ InputPathIsFolder,
+
+ ///
+ /// 资源文件不存在
+ ///
+ AssetPathNotExists,
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/BundleCollector/AssetSearch/ECollectAssetSearchError.cs.meta b/Assets/YooAsset/Editor/BundleCollector/AssetSearch/ECollectAssetSearchError.cs.meta
new file mode 100644
index 00000000..fd7296fb
--- /dev/null
+++ b/Assets/YooAsset/Editor/BundleCollector/AssetSearch/ECollectAssetSearchError.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9a2c8a878d6041b4d8bad2a2d2f1896d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/BundleCollector/BundleCollector.cs b/Assets/YooAsset/Editor/BundleCollector/BundleCollector.cs
index 4ae4b92c..2bd585a4 100644
--- a/Assets/YooAsset/Editor/BundleCollector/BundleCollector.cs
+++ b/Assets/YooAsset/Editor/BundleCollector/BundleCollector.cs
@@ -60,21 +60,22 @@ namespace YooAsset.Editor
/// 如果收集器配置有效返回 true
public bool IsValid()
{
- if (AssetDatabase.LoadAssetAtPath(CollectPath) == null)
+ string assetGUID = AssetDatabase.AssetPathToGUID(CollectPath);
+ if (string.IsNullOrEmpty(assetGUID))
return false;
if (CollectorType == ECollectorType.None)
return false;
- if (BundleCollectorSettingData.HasAddressRuleName(AddressRuleName) == false)
- return false;
-
if (BundleCollectorSettingData.HasBundlePackRuleName(PackRuleName) == false)
return false;
if (BundleCollectorSettingData.HasAssetFilterRuleName(FilterRuleName) == false)
return false;
+ if (BundleCollectorSettingData.HasAddressRuleName(AddressRuleName) == false)
+ return false;
+
return true;
}
diff --git a/Assets/YooAsset/Editor/BundleCollector/BundleCollectorWindow.cs b/Assets/YooAsset/Editor/BundleCollector/BundleCollectorWindow.cs
index ec42ca91..7ae54973 100644
--- a/Assets/YooAsset/Editor/BundleCollector/BundleCollectorWindow.cs
+++ b/Assets/YooAsset/Editor/BundleCollector/BundleCollectorWindow.cs
@@ -25,6 +25,8 @@ namespace YooAsset.Editor
window.minSize = new Vector2(800, 600);
}
+ private const string PlaceholderClass = "search-placeholder";
+
private Button _saveButton;
private List _collectorTypeList;
private List _groupActiveRuleList;
@@ -35,6 +37,11 @@ namespace YooAsset.Editor
private VisualElement _helpBoxContainer;
+ private ToolbarSearchField _searchField;
+ private TextField _searchTextField;
+ private Button _searchButton;
+ private Label _searchResultLabel;
+
private Button _globalSettingsButton;
private Button _packageSettingsButton;
@@ -66,6 +73,8 @@ namespace YooAsset.Editor
private ScrollView _collectorScrollView;
private PopupField _activeRulePopupField;
+ private string _highlightAssetPath;
+ private int _highlightCollectorIndex = -1;
private int _lastModifyPackageIndex = 0;
private int _lastModifyGroupIndex = 0;
private bool _showGlobalSettings = false;
@@ -219,6 +228,44 @@ namespace YooAsset.Editor
_saveButton = root.Q