diff --git a/Assets/YooAsset/Editor/BundleCollector/BundleCollectorSettingData.cs b/Assets/YooAsset/Editor/BundleCollector/BundleCollectorSettingData.cs index 93e43ebf..2509b817 100644 --- a/Assets/YooAsset/Editor/BundleCollector/BundleCollectorSettingData.cs +++ b/Assets/YooAsset/Editor/BundleCollector/BundleCollectorSettingData.cs @@ -175,6 +175,17 @@ namespace YooAsset.Editor } } + /// + /// 工程中是否已存在收集器配置文件 + /// + /// 存在返回 true + public static bool HasSettingAsset() + { + string typeName = nameof(BundleCollectorSetting); + var guids = AssetDatabase.FindAssets($"t:{typeName}"); + return guids != null && guids.Length > 0; + } + /// /// 存储配置文件 /// diff --git a/Assets/YooAsset/Editor/BundleCollector/BundleCollectorWindow.cs b/Assets/YooAsset/Editor/BundleCollector/BundleCollectorWindow.cs index 7ae54973..f21d654c 100644 --- a/Assets/YooAsset/Editor/BundleCollector/BundleCollectorWindow.cs +++ b/Assets/YooAsset/Editor/BundleCollector/BundleCollectorWindow.cs @@ -19,10 +19,30 @@ namespace YooAsset.Editor /// [MenuItem("YooAsset/Bundle Collector", false, 101)] public static void OpenWindow() + { + OpenWindowInternal(); + } + + /// + /// 打开资源收集器窗口并定位到指定的收集器 + /// + /// 包裹名称 + /// 分组名称 + /// 收集路径 + public static void OpenWindow(string packageName, string groupName, string collectPath) + { + BundleCollectorWindow window = OpenWindowInternal(); + window.SetFocusCollector(packageName, groupName, collectPath); + window.RefreshWindow(); + window.Focus(); + } + + private static BundleCollectorWindow OpenWindowInternal() { Type[] dockedTypes = EditorWindowDefine.GetDockedWindowTypes(); BundleCollectorWindow window = GetWindow("Bundle Collector", true, dockedTypes); window.minSize = new Vector2(800, 600); + return window; } private const string PlaceholderClass = "search-placeholder"; @@ -77,6 +97,7 @@ namespace YooAsset.Editor private int _highlightCollectorIndex = -1; private int _lastModifyPackageIndex = 0; private int _lastModifyGroupIndex = 0; + private bool _hasFocusCollector = false; private bool _showGlobalSettings = false; private bool _showPackageSettings = false; @@ -471,7 +492,8 @@ namespace YooAsset.Editor private void RefreshWindow() { _highlightAssetPath = null; - _highlightCollectorIndex = -1; + if (_hasFocusCollector == false) + _highlightCollectorIndex = -1; _groupContainer.visible = false; _collectorContainer.visible = false; @@ -508,6 +530,7 @@ namespace YooAsset.Editor { _highlightAssetPath = null; _highlightCollectorIndex = -1; + _hasFocusCollector = false; FillCollectorViewData(); string searchInput = GetSearchInput(); @@ -577,6 +600,46 @@ namespace YooAsset.Editor return ruleDisplayName.ClassName; } + // 焦点相关 + private void SetFocusCollector(string packageName, string groupName, string collectPath) + { + var packages = BundleCollectorSettingData.Setting.Packages; + int packageIndex = packages.FindIndex(item => item.PackageName == packageName); + if (packageIndex < 0) + { + Debug.LogWarning($"Package not found: '{packageName}'."); + _highlightCollectorIndex = -1; + _hasFocusCollector = false; + return; + } + + var package = packages[packageIndex]; + int groupIndex = package.Groups.FindIndex(item => item.GroupName == groupName); + if (groupIndex < 0) + { + Debug.LogWarning($"Group not found: '{groupName}' in package '{packageName}'."); + _highlightCollectorIndex = -1; + _hasFocusCollector = false; + return; + } + + var group = package.Groups[groupIndex]; + int collectorIndex = group.Collectors.FindIndex(item => string.Equals(item.CollectPath, collectPath, StringComparison.OrdinalIgnoreCase)); + if (collectorIndex < 0) + { + Debug.LogWarning($"Collector not found: '{collectPath}'."); + _highlightCollectorIndex = -1; + _hasFocusCollector = false; + return; + } + + _highlightAssetPath = null; + _highlightCollectorIndex = collectorIndex; + _lastModifyPackageIndex = packageIndex; + _lastModifyGroupIndex = groupIndex; + _hasFocusCollector = true; + } + // 搜索栏相关 private void ShowSearchResult(string message, Color color) { @@ -898,6 +961,7 @@ namespace YooAsset.Editor if (foldout != null) foldout.value = true; _highlightCollectorIndex = -1; + _hasFocusCollector = false; } } private VisualElement MakeCollectorListViewItem() diff --git a/Assets/YooAsset/Samples~/Extension Sample/Editor/CollectorInspector.meta b/Assets/YooAsset/Samples~/Extension Sample/Editor/CollectorInspector.meta new file mode 100644 index 00000000..9c86ef57 --- /dev/null +++ b/Assets/YooAsset/Samples~/Extension Sample/Editor/CollectorInspector.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dd8a9e643275082438da0f2f5c4f7f68 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Samples~/Extension Sample/Editor/CollectorInspector/BundleCollectorGUIDraw.cs b/Assets/YooAsset/Samples~/Extension Sample/Editor/CollectorInspector/BundleCollectorGUIDraw.cs new file mode 100644 index 00000000..cab1d758 --- /dev/null +++ b/Assets/YooAsset/Samples~/Extension Sample/Editor/CollectorInspector/BundleCollectorGUIDraw.cs @@ -0,0 +1,92 @@ +using UnityEditor; +using UnityEngine; + +namespace YooAsset.Editor +{ + /// + /// 扩展的 IMGUI 绘制辅助方法集合 + /// + internal static class BundleCollectorGUIDraw + { + /// + /// 绘制区块标题 + /// + /// 标题文本 + public static void DrawSectionTitle(string title) + { + EditorGUILayout.LabelField(title, BundleCollectorGUIStyle.TitleStyle); + EditorGUILayout.Space(2); + } + + /// + /// 绘制一个带字段名的只读文本字段 + /// + /// 字段名 + /// 字段值 + /// 是否置灰整行 + public static void DrawLabelField(string label, string value, bool disabled = false) + { + using (new EditorGUI.DisabledScope(disabled)) + { + using (new EditorGUILayout.HorizontalScope()) + { + GUILayout.Label(label, BundleCollectorGUIStyle.FieldLabelStyle, GUILayout.Width(EditorGUIUtility.labelWidth)); + EditorGUILayout.LabelField(string.IsNullOrEmpty(value) ? "-" : value); + } + } + } + + /// + /// 绘制一个带字段名的延迟文本输入框 + /// + /// 字段名 + /// 当前文本值 + /// 新的文本值 + public static string DrawTextField(string label, string value) + { + using (new EditorGUILayout.HorizontalScope()) + { + GUILayout.Label(label, BundleCollectorGUIStyle.FieldLabelStyle, GUILayout.Width(EditorGUIUtility.labelWidth)); + return EditorGUILayout.DelayedTextField(value); + } + } + + /// + /// 绘制一个带字段名的下拉框 + /// + /// 字段名 + /// 当前选项索引 + /// 下拉选项 + /// 新的选项索引 + public static int DrawPopupField(string label, int index, string[] displayedOptions) + { + using (new EditorGUILayout.HorizontalScope()) + { + GUILayout.Label(label, BundleCollectorGUIStyle.FieldLabelStyle, GUILayout.Width(EditorGUIUtility.labelWidth)); + return EditorGUILayout.Popup(index, displayedOptions); + } + } + + /// + /// 绘制规则选择行 + /// + /// 字段标签 + /// 显示名称列表 + /// 当前选中索引 + /// 新选中的索引 + /// 规则索引发生变化返回 true + public static bool TryDrawRuleSelection(string label, string[] displayNames, int currentIndex, out int newIndex) + { + newIndex = -1; + if (displayNames == null || displayNames.Length == 0) + { + using (new EditorGUI.DisabledScope(true)) DrawPopupField(label, 0, new[] { "" }); + return false; + } + + currentIndex = Mathf.Clamp(currentIndex, 0, displayNames.Length - 1); + newIndex = DrawPopupField(label, currentIndex, displayNames); + return newIndex != currentIndex; + } + } +} diff --git a/Assets/YooAsset/Samples~/Extension Sample/Editor/CollectorInspector/BundleCollectorGUIDraw.cs.meta b/Assets/YooAsset/Samples~/Extension Sample/Editor/CollectorInspector/BundleCollectorGUIDraw.cs.meta new file mode 100644 index 00000000..ee644678 --- /dev/null +++ b/Assets/YooAsset/Samples~/Extension Sample/Editor/CollectorInspector/BundleCollectorGUIDraw.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fb2a2401e7c68a64496c3194543aff6b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Samples~/Extension Sample/Editor/CollectorInspector/BundleCollectorGUIStyle.cs b/Assets/YooAsset/Samples~/Extension Sample/Editor/CollectorInspector/BundleCollectorGUIStyle.cs new file mode 100644 index 00000000..3ec471a9 --- /dev/null +++ b/Assets/YooAsset/Samples~/Extension Sample/Editor/CollectorInspector/BundleCollectorGUIStyle.cs @@ -0,0 +1,71 @@ +using UnityEditor; +using UnityEngine; + +namespace YooAsset.Editor +{ + /// + /// 扩展的 IMGUI 样式集合 + /// + internal static class BundleCollectorGUIStyle + { + // 注意:GUIStyle 依赖 GUI 皮肤,不能在静态构造里创建,需延迟到绘制时初始化。 + private static GUIStyle _titleStyle; + private static GUIStyle _fieldLabelStyle; + private static GUIStyle _sectionStyle; + + /// + /// 区块标题样式:保持正文字号,仅通过加粗和间距与内容区分。 + /// + public static GUIStyle TitleStyle + { + get + { + if (_titleStyle == null) + { + _titleStyle = new GUIStyle(EditorStyles.boldLabel) + { + fontStyle = FontStyle.Bold, + margin = new RectOffset(0, 0, 2, 4), + }; + } + return _titleStyle; + } + } + + /// + /// 字段名样式:保持正文字号。 + /// + public static GUIStyle FieldLabelStyle + { + get + { + if (_fieldLabelStyle == null) + { + _fieldLabelStyle = new GUIStyle(EditorStyles.label) + { + fontStyle = FontStyle.Normal, + }; + } + return _fieldLabelStyle; + } + } + + /// + /// 分组卡片样式:基于 helpBox 增加内边距,让内容不贴边。 + /// + public static GUIStyle SectionStyle + { + get + { + if (_sectionStyle == null) + { + _sectionStyle = new GUIStyle(EditorStyles.helpBox) + { + padding = new RectOffset(6, 6, 5, 6), + }; + } + return _sectionStyle; + } + } + } +} diff --git a/Assets/YooAsset/Samples~/Extension Sample/Editor/CollectorInspector/BundleCollectorGUIStyle.cs.meta b/Assets/YooAsset/Samples~/Extension Sample/Editor/CollectorInspector/BundleCollectorGUIStyle.cs.meta new file mode 100644 index 00000000..f56756ea --- /dev/null +++ b/Assets/YooAsset/Samples~/Extension Sample/Editor/CollectorInspector/BundleCollectorGUIStyle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8f37650836ac1ca4ab53da11208bace4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Samples~/Extension Sample/Editor/CollectorInspector/BundleCollectorInspector.cs b/Assets/YooAsset/Samples~/Extension Sample/Editor/CollectorInspector/BundleCollectorInspector.cs new file mode 100644 index 00000000..ae2fafc5 --- /dev/null +++ b/Assets/YooAsset/Samples~/Extension Sample/Editor/CollectorInspector/BundleCollectorInspector.cs @@ -0,0 +1,456 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace YooAsset.Editor +{ + /// + /// 资源收集器的 Inspector 扩展 + /// + [InitializeOnLoad] + internal static class BundleCollectorInspector + { + private struct CollectorContext + { + public BundleCollectorPackage Package; + public BundleCollectorGroup Group; + public BundleCollector Collector; + } + + private static readonly string[] CollectorTypeNames = + { + nameof(ECollectorType.MainAssetCollector), + nameof(ECollectorType.StaticAssetCollector), + nameof(ECollectorType.DependAssetCollector), + }; + + private static int _createPackageIndex; + private static int _createGroupIndex; + + static BundleCollectorInspector() + { + UnityEditor.Editor.finishedDefaultHeaderGUI -= OnPostHeaderGUI; + UnityEditor.Editor.finishedDefaultHeaderGUI += OnPostHeaderGUI; + } + + /// + /// Inspector 默认头部绘制完成后的回调 + /// + /// 当前正在绘制的 Inspector 编辑器实例 + private static void OnPostHeaderGUI(UnityEditor.Editor editor) + { + // 注意:多目标选择的时候不绘制 + if (editor.targets != null && editor.targets.Length > 1) + return; + + UnityEngine.Object target = editor.target; + if (target == null) + return; + + // 检测选择的路径是否合法 + string assetPath = AssetDatabase.GetAssetPath(target); + if (string.IsNullOrEmpty(assetPath)) + return; + if (assetPath == "Assets") + return; + if (assetPath.StartsWith("Assets/", StringComparison.OrdinalIgnoreCase) == false) + return; + if (AssetDatabase.IsValidFolder(assetPath) == false) + return; + + // 检测配置文件是否存在 + if (BundleCollectorSettingData.HasSettingAsset() == false) + { + EditorGUILayout.Space(); + EditorGUILayout.LabelField("YooAsset", "BundleCollectorSetting.asset not found."); + return; + } + + // 根据当前文件夹是否已经配置,动态切换展示模式。 + EditorGUILayout.Space(); + using (new EditorGUILayout.VerticalScope(BundleCollectorGUIStyle.SectionStyle)) + { + bool isFindCollector = TryGetCollector(assetPath, out CollectorContext collectorContext); + if (isFindCollector) + { + DrawOpenCollectorHeader(collectorContext); + DrawTargetCollectorContent(collectorContext); + } + else + { + DrawCreateCollectorHeader(assetPath); + DrawCreateCollectorSelector(); + } + } + } + private static void DrawCreateCollectorHeader(string assetPath) + { + using (new EditorGUILayout.HorizontalScope()) + { + EditorGUILayout.LabelField("YooAsset", EditorStyles.boldLabel, GUILayout.Width(95)); + GUILayout.FlexibleSpace(); + + bool hasCreateTarget = TryGetCreateCollectorTarget(out var package, out var group); + using (new EditorGUI.DisabledScope(hasCreateTarget == false)) + { + if (GUILayout.Button("Create Collector", GUILayout.Width(120))) + { + TryAddCollector(assetPath, package, group, out _); + } + } + } + } + private static void DrawCreateCollectorSelector() + { + using (new EditorGUILayout.VerticalScope(BundleCollectorGUIStyle.SectionStyle)) + { + BundleCollectorGUIDraw.DrawSectionTitle("Package & Group"); + + var setting = BundleCollectorSettingData.Setting; + if (setting == null || setting.Packages.Count == 0) + { + EditorGUILayout.HelpBox("Please create a Package in the Bundle Collector window first.", MessageType.Info); + return; + } + + ClampCreateTargetIndices(); + string[] packageNames = setting.Packages.Select(item => item.PackageName).ToArray(); + int newPackageIndex = BundleCollectorGUIDraw.DrawPopupField("Package", _createPackageIndex, packageNames); + if (newPackageIndex != _createPackageIndex) + { + _createPackageIndex = newPackageIndex; + _createGroupIndex = 0; + } + + var package = setting.Packages[_createPackageIndex]; + if (package.Groups.Count == 0) + { + EditorGUILayout.HelpBox("Please create a Group in the Bundle Collector window first.", MessageType.Info); + return; + } + + string[] groupNames = package.Groups.Select(item => item.GroupName).ToArray(); + _createGroupIndex = BundleCollectorGUIDraw.DrawPopupField("Group", _createGroupIndex, groupNames); + } + } + private static void DrawOpenCollectorHeader(CollectorContext collectorContext) + { + using (new EditorGUILayout.HorizontalScope()) + { + EditorGUILayout.LabelField("YooAsset", EditorStyles.boldLabel, GUILayout.Width(95)); + GUILayout.FlexibleSpace(); + + if (GUILayout.Button("Open Collector", GUILayout.Width(120))) + { + BundleCollectorWindow.OpenWindow(collectorContext.Package.PackageName, collectorContext.Group.GroupName, collectorContext.Collector.CollectPath); + } + } + } + private static void DrawTargetCollectorContent(CollectorContext collectorContext) + { + var package = collectorContext.Package; + var group = collectorContext.Group; + var collector = collectorContext.Collector; + var setting = BundleCollectorSettingData.Setting; + bool showAlias = setting.ShowEditorAlias; + + float oldLabelWidth = EditorGUIUtility.labelWidth; + EditorGUIUtility.labelWidth = 100; + + try + { + // 区块:包裹与分组 + using (new EditorGUILayout.VerticalScope(BundleCollectorGUIStyle.SectionStyle)) + { + BundleCollectorGUIDraw.DrawSectionTitle("Package & Group"); + + // 包裹 + var packageNames = setting.Packages.Select(p => p.PackageName).ToArray(); + int packageIndex = Mathf.Max(0, Array.IndexOf(packageNames, package.PackageName)); + int newPackageIndex = BundleCollectorGUIDraw.DrawPopupField("Package", packageIndex, packageNames); + if (newPackageIndex != packageIndex && MoveCollectorToPackage(collector, group, setting.Packages[newPackageIndex])) + return; + + // 分组 + var groupNames = package.Groups.Select(g => g.GroupName).ToArray(); + int groupIndex = Mathf.Max(0, Array.IndexOf(groupNames, group.GroupName)); + int newGroupIndex = BundleCollectorGUIDraw.DrawPopupField("Group", groupIndex, groupNames); + if (newGroupIndex != groupIndex) + { + MoveCollectorToGroup(collector, group, package.Groups[newGroupIndex]); + return; + } + } + + // 区块:收集器配置 + using (new EditorGUILayout.VerticalScope(BundleCollectorGUIStyle.SectionStyle)) + { + BundleCollectorGUIDraw.DrawSectionTitle("Collector Settings"); + BundleCollectorGUIDraw.DrawLabelField("Collect Path", collector.CollectPath); + + // 收集器类型 + int typeIndex = Mathf.Max(0, Array.IndexOf(CollectorTypeNames, collector.CollectorType.ToString())); + int newTypeIndex = BundleCollectorGUIDraw.DrawPopupField("Collector Type", typeIndex, CollectorTypeNames); + if (newTypeIndex != typeIndex) + { + RecordUndo("YooAsset.Inspector Modify CollectorType"); + collector.CollectorType = EditorStringUtility.ParseEnum(CollectorTypeNames[newTypeIndex]); + CommitModify(group, collector); + } + + // 地址规则(仅对主资源收集器生效) + bool isMainCollector = collector.CollectorType == ECollectorType.MainAssetCollector; + using (new EditorGUI.DisabledScope(isMainCollector == false)) + { + var addressRules = BundleCollectorSettingData.GetAddressRuleNames(); + if (BundleCollectorGUIDraw.TryDrawRuleSelection("Address Rule", GetRuleDisplayNames(addressRules, showAlias), GetRuleIndex(addressRules, collector.AddressRuleName), out int newAddressRuleIndex)) + { + RecordUndo("YooAsset.Inspector Modify AddressRule"); + collector.AddressRuleName = addressRules[newAddressRuleIndex].ClassName; + CommitModify(group, collector); + } + } + + // 打包规则 + var packRules = BundleCollectorSettingData.GetBundlePackRuleNames(); + if (BundleCollectorGUIDraw.TryDrawRuleSelection("Pack Rule", GetRuleDisplayNames(packRules, showAlias), GetRuleIndex(packRules, collector.PackRuleName), out int newPackRuleIndex)) + { + RecordUndo("YooAsset.Inspector Modify PackRule"); + collector.PackRuleName = packRules[newPackRuleIndex].ClassName; + CommitModify(group, collector); + } + + // 过滤规则 + var filterRules = BundleCollectorSettingData.GetAssetFilterRuleNames(); + if (BundleCollectorGUIDraw.TryDrawRuleSelection("Filter Rule", GetRuleDisplayNames(filterRules, showAlias), GetRuleIndex(filterRules, collector.FilterRuleName), out int newFilterRuleIndex)) + { + RecordUndo("YooAsset.Inspector Modify FilterRule"); + collector.FilterRuleName = filterRules[newFilterRuleIndex].ClassName; + CommitModify(group, collector); + } + + // 用户数据(延迟提交,避免逐键写盘) + string newUserData = BundleCollectorGUIDraw.DrawTextField("UserData", collector.UserData); + if (newUserData != collector.UserData) + { + RecordUndo("YooAsset.Inspector Modify UserData"); + collector.UserData = newUserData; + CommitModify(group, collector); + } + + // 资源标签(仅对主资源收集器生效) + using (new EditorGUI.DisabledScope(isMainCollector == false)) + { + string newTags = BundleCollectorGUIDraw.DrawTextField("Tags", collector.AssetTags); + if (newTags != collector.AssetTags) + { + RecordUndo("YooAsset.Inspector Modify AssetTags"); + collector.AssetTags = newTags; + CommitModify(group, collector); + } + } + } + } + finally + { + EditorGUIUtility.labelWidth = oldLabelWidth; + } + } + + /// + /// 获取规则列表用于下拉框展示的名称数组 + /// + private static string[] GetRuleDisplayNames(List rules, bool showAlias) + { + if (rules == null || rules.Count == 0) + return Array.Empty(); + + return rules.Select(rule => showAlias ? rule.DisplayName : rule.ClassName).ToArray(); + } + + /// + /// 根据规则类名查找规则在列表中的索引 + /// + private static int GetRuleIndex(List rules, string className) + { + if (rules == null || rules.Count == 0) + return -1; + + return Mathf.Max(0, rules.FindIndex(rule => rule.ClassName == className)); + } + + #region 数据查找与编辑 + /// + /// 获取当前创建收集器所选择的目标包裹和分组 + /// + private static bool TryGetCreateCollectorTarget(out BundleCollectorPackage package, out BundleCollectorGroup group) + { + package = null; + group = null; + + var setting = BundleCollectorSettingData.Setting; + if (setting == null || setting.Packages.Count == 0) + return false; + + ClampCreateTargetIndices(); + package = setting.Packages[_createPackageIndex]; + if (package.Groups.Count == 0) + return false; + + group = package.Groups[_createGroupIndex]; + return true; + } + + /// + /// 将创建目标的包裹/分组索引收敛到当前配置的合法范围 + /// + private static void ClampCreateTargetIndices() + { + var setting = BundleCollectorSettingData.Setting; + if (setting == null || setting.Packages.Count == 0) + { + _createPackageIndex = 0; + _createGroupIndex = 0; + return; + } + + _createPackageIndex = Mathf.Clamp(_createPackageIndex, 0, setting.Packages.Count - 1); + var package = setting.Packages[_createPackageIndex]; + if (package.Groups.Count == 0) + { + _createGroupIndex = 0; + return; + } + + _createGroupIndex = Mathf.Clamp(_createGroupIndex, 0, package.Groups.Count - 1); + } + + /// + /// 按文件夹路径精确获取已配置的收集器信息 + /// + private static bool TryGetCollector(string folderPath, out CollectorContext result) + { + result = default; + + var setting = BundleCollectorSettingData.Setting; + if (setting == null) + return false; + + foreach (var package in setting.Packages) + { + foreach (var group in package.Groups) + { + foreach (var collector in group.Collectors) + { + if (string.Equals(collector.CollectPath, folderPath, StringComparison.OrdinalIgnoreCase)) + { + result = new CollectorContext + { + Package = package, + Group = group, + Collector = collector, + }; + return true; + } + } + } + } + return false; + } + + /// + /// 为指定文件夹在目标包裹分组下创建收集器 + /// + private static bool TryAddCollector(string folderPath, BundleCollectorPackage package, BundleCollectorGroup group, out CollectorContext result) + { + result = default; + if (package == null || group == null) + return false; + + RecordUndo("YooAsset.Inspector Add Collector"); + var collector = new BundleCollector + { + CollectPath = folderPath, + CollectorGUID = AssetDatabase.AssetPathToGUID(folderPath), + }; + BundleCollectorSettingData.CreateCollector(group, collector); + BundleCollectorSettingData.SaveFile(); + + result = new CollectorContext + { + Package = package, + Group = group, + Collector = collector, + }; + return true; + } + + /// + /// 将收集器移动到目标包裹的第一个分组 + /// + /// 要移动的收集器实例 + /// 原分组 + /// 目标包裹 + /// 目标包裹无分组或无需移动时返回 false + private static bool MoveCollectorToPackage(BundleCollector collector, BundleCollectorGroup fromGroup, BundleCollectorPackage toPackage) + { + if (toPackage.Groups.Count == 0) + { + Debug.LogWarning($"Package '{toPackage.PackageName}' has no group. Please create a group first."); + return false; + } + + var toGroup = toPackage.Groups[0]; + if (toGroup == fromGroup) + return false; + + RecordUndo("YooAsset.Inspector Move Collector Package"); + fromGroup.Collectors.Remove(collector); + toGroup.Collectors.Add(collector); + BundleCollectorSettingData.ModifyCollector(toGroup, collector); + BundleCollectorSettingData.SaveFile(); + return true; + } + + /// + /// 将收集器在同一包裹内移动到目标分组 + /// + /// 要移动的收集器实例 + /// 原分组 + /// 目标分组 + private static void MoveCollectorToGroup(BundleCollector collector, BundleCollectorGroup fromGroup, BundleCollectorGroup toGroup) + { + if (toGroup == fromGroup) + return; + + RecordUndo("YooAsset.Inspector Move Collector Group"); + fromGroup.Collectors.Remove(collector); + toGroup.Collectors.Add(collector); + BundleCollectorSettingData.ModifyCollector(toGroup, collector); + BundleCollectorSettingData.SaveFile(); + } + + /// + /// 标记收集器已修改并持久化配置文件 + /// + /// 收集器所属分组 + /// 被修改的收集器 + private static void CommitModify(BundleCollectorGroup group, BundleCollector collector) + { + BundleCollectorSettingData.ModifyCollector(group, collector); + BundleCollectorSettingData.SaveFile(); + } + + /// + /// 在修改配置前登记 Undo,使操作可撤销。 + /// + /// Undo 操作名称 + private static void RecordUndo(string name) + { + Undo.RecordObject(BundleCollectorSettingData.Setting, name); + } + #endregion + } +} diff --git a/Assets/YooAsset/Samples~/Extension Sample/Editor/CollectorInspector/BundleCollectorInspector.cs.meta b/Assets/YooAsset/Samples~/Extension Sample/Editor/CollectorInspector/BundleCollectorInspector.cs.meta new file mode 100644 index 00000000..68313a97 --- /dev/null +++ b/Assets/YooAsset/Samples~/Extension Sample/Editor/CollectorInspector/BundleCollectorInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9f06fac18179b404988b68a675c421af +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: