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