diff --git a/Assets/YooAsset/Editor/AssetBundleGrouper.meta b/Assets/YooAsset/Editor/AssetBundleGrouper.meta
new file mode 100644
index 0000000..de219f5
--- /dev/null
+++ b/Assets/YooAsset/Editor/AssetBundleGrouper.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: b19f23ac31124274d942d32bec434450
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleCollector.cs b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleCollector.cs
new file mode 100644
index 0000000..90708ab
--- /dev/null
+++ b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleCollector.cs
@@ -0,0 +1,176 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEditor;
+
+namespace YooAsset.Editor
+{
+ [Serializable]
+ public class AssetBundleCollector
+ {
+ ///
+ /// 收集路径
+ /// 注意:支持文件夹或单个资源文件
+ ///
+ public string CollectPath = string.Empty;
+
+ ///
+ /// 打包规则类名
+ ///
+ public string PackRuleName = string.Empty;
+
+ ///
+ /// 过滤规则类名
+ ///
+ public string FilterRuleName = string.Empty;
+
+ ///
+ /// 不写入资源列表
+ ///
+ public bool NotWriteToAssetList = false;
+
+ ///
+ /// 资源分类标签
+ ///
+ public string AssetTags = string.Empty;
+
+
+ ///
+ /// 获取打包收集的资源文件
+ ///
+ public List GetAllCollectAssets(AssetBundleGrouper grouper)
+ {
+ Dictionary result = new Dictionary(1000);
+ bool isRawAsset = PackRuleName == nameof(PackRawFile);
+
+ // 如果是文件夹
+ if (AssetDatabase.IsValidFolder(CollectPath))
+ {
+ string collectDirectory = CollectPath;
+ string[] findAssets = EditorTools.FindAssets(EAssetSearchType.All, collectDirectory);
+ foreach (string assetPath in findAssets)
+ {
+ if (IsValidateAsset(assetPath) == false)
+ continue;
+ if (IsCollectAsset(assetPath) == false)
+ continue;
+ if (result.ContainsKey(assetPath) == false)
+ {
+ string bundleName = GetBundleName(grouper, assetPath);
+ List assetTags = GetAssetTags(grouper);
+ var collectAssetInfo = new CollectAssetInfo(bundleName, assetPath, assetTags, isRawAsset, NotWriteToAssetList);
+ collectAssetInfo.DependAssets = GetAllDependencies(assetPath);
+ result.Add(assetPath, collectAssetInfo);
+ }
+ else
+ {
+ throw new Exception($"The collecting asset file is existed : {assetPath} in collector : {CollectPath}");
+ }
+ }
+ }
+ else
+ {
+ string assetPath = CollectPath;
+ if (result.ContainsKey(assetPath) == false)
+ {
+ if (isRawAsset && NotWriteToAssetList)
+ UnityEngine.Debug.LogWarning($"Are you sure raw file are not write to asset list : {assetPath}");
+
+ string bundleName = GetBundleName(grouper, assetPath);
+ List assetTags = GetAssetTags(grouper);
+ var collectAssetInfo = new CollectAssetInfo(bundleName, assetPath, assetTags, isRawAsset, NotWriteToAssetList);
+ result.Add(assetPath, collectAssetInfo);
+ }
+ else
+ {
+ throw new Exception($"The collecting asset file is existed : {assetPath} in collector : {CollectPath}");
+ }
+ }
+
+ // 返回列表
+ return result.Values.ToList();
+ }
+
+ private bool IsValidateAsset(string assetPath)
+ {
+ if (assetPath.StartsWith("Assets/") == false && assetPath.StartsWith("Packages/") == false)
+ return false;
+
+ if (AssetDatabase.IsValidFolder(assetPath))
+ return false;
+
+ // 注意:忽略编辑器下的类型资源
+ Type type = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
+ if (type == typeof(LightingDataAsset))
+ return false;
+
+ string ext = System.IO.Path.GetExtension(assetPath);
+ if (ext == "" || ext == ".dll" || ext == ".cs" || ext == ".js" || ext == ".boo" || ext == ".meta")
+ return false;
+
+ return true;
+ }
+ private bool IsCollectAsset(string assetPath)
+ {
+ // 如果收集全路径着色器
+ if (AssetBundleGrouperSettingData.Setting.AutoCollectShaders)
+ {
+ Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
+ if (assetType == typeof(UnityEngine.Shader))
+ return true;
+ }
+
+ // 根据规则设置过滤资源文件
+ IFilterRule filterRuleInstance = AssetBundleGrouperSettingData.GetFilterRuleInstance(FilterRuleName);
+ return filterRuleInstance.IsCollectAsset(assetPath);
+ }
+ private string GetBundleName(AssetBundleGrouper grouper, string assetPath)
+ {
+ // 如果收集全路径着色器
+ if (AssetBundleGrouperSettingData.Setting.AutoCollectShaders)
+ {
+ System.Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
+ if (assetType == typeof(UnityEngine.Shader))
+ {
+ return RevisedBundleName(AssetBundleGrouperSettingData.Setting.ShadersBundleName);
+ }
+ }
+
+ // 根据规则设置获取资源包名称
+ IPackRule packRuleInstance = AssetBundleGrouperSettingData.GetPackRuleInstance(PackRuleName);
+ string bundleName = packRuleInstance.GetBundleName(new PackRuleData(assetPath, CollectPath, grouper.GrouperName));
+ return RevisedBundleName(bundleName);
+ }
+ private List GetAssetTags(AssetBundleGrouper grouper)
+ {
+ List tags = StringUtility.StringToStringList(grouper.AssetTags, ';');
+ List temper = StringUtility.StringToStringList(AssetTags, ';');
+ tags.AddRange(temper);
+ return tags;
+ }
+ private List GetAllDependencies(string mainAssetPath)
+ {
+ List result = new List();
+ string[] depends = AssetDatabase.GetDependencies(mainAssetPath, true);
+ foreach (string assetPath in depends)
+ {
+ if (IsValidateAsset(assetPath))
+ {
+ // 注意:排除主资源对象
+ if (assetPath != mainAssetPath)
+ result.Add(assetPath);
+ }
+ }
+ return result;
+ }
+
+
+ ///
+ /// 修正资源包名
+ ///
+ public static string RevisedBundleName(string bundleName)
+ {
+ return EditorTools.GetRegularPath(bundleName).ToLower();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleCollector.cs.meta b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleCollector.cs.meta
new file mode 100644
index 0000000..ef9c7c9
--- /dev/null
+++ b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleCollector.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f79866c315d53ef4480d6fa4083c09ad
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouper.cs b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouper.cs
new file mode 100644
index 0000000..b462ef2
--- /dev/null
+++ b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouper.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+using UnityEditor;
+
+namespace YooAsset.Editor
+{
+ [Serializable]
+ public class AssetBundleGrouper
+ {
+ ///
+ /// 分组名称
+ ///
+ public string GrouperName = string.Empty;
+
+ ///
+ /// 分组描述
+ ///
+ public string GrouperDesc = string.Empty;
+
+ ///
+ /// 资源分类标签
+ ///
+ public string AssetTags = string.Empty;
+
+ ///
+ /// 分组的收集器列表
+ ///
+ public List Collectors = new List();
+
+
+ ///
+ /// 获取打包收集的资源文件
+ ///
+ public List GetAllCollectAssets()
+ {
+ Dictionary result = new Dictionary(10000);
+ foreach(var collector in Collectors)
+ {
+ var temper = collector.GetAllCollectAssets(this);
+ foreach(var assetInfo in temper)
+ {
+ if(result.ContainsKey(assetInfo.AssetPath) == false)
+ {
+ result.Add(assetInfo.AssetPath, assetInfo);
+ }
+ else
+ {
+ throw new Exception($"The collecting asset file is existed : {assetInfo.AssetPath} in grouper : {GrouperName}");
+ }
+ }
+ }
+ return result.Values.ToList();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouper.cs.meta b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouper.cs.meta
new file mode 100644
index 0000000..8c08f09
--- /dev/null
+++ b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouper.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e9f7615a761107d4ebf96d66be2f6b45
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperConfigDefine.cs b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperConfigDefine.cs
new file mode 100644
index 0000000..c1f48b6
--- /dev/null
+++ b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperConfigDefine.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace YooAsset.Editor
+{
+ public class AssetBundleGrouperConfigDefine
+ {
+ public const string XmlGrouper = "Grouper";
+ public const string XmlCollector = "Collector";
+ public const string XmlDirectory = "CollectPath";
+ public const string XmlPackRule = "PackRule";
+ public const string XmlFilterRule = "FilterRule";
+ public const string XmlNotWriteToAssetList = "NotWriteToAssetList";
+ public const string XmlAssetTags = "AssetTags";
+
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperConfigDefine.cs.meta b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperConfigDefine.cs.meta
new file mode 100644
index 0000000..0325996
--- /dev/null
+++ b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperConfigDefine.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f2190cc6d8995aa458ded22ffd7fc1e0
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperConfigExporter.cs b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperConfigExporter.cs
new file mode 100644
index 0000000..47169fd
--- /dev/null
+++ b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperConfigExporter.cs
@@ -0,0 +1,14 @@
+using System;
+using System.IO;
+using System.Xml;
+using System.Collections.Generic;
+using UnityEditor;
+using UnityEngine;
+
+namespace YooAsset.Editor
+{
+ public class AssetBundleGrouperConfigExporter
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperConfigExporter.cs.meta b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperConfigExporter.cs.meta
new file mode 100644
index 0000000..7168819
--- /dev/null
+++ b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperConfigExporter.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 57959ce1a0581284c8bb37655a81dc1e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperConfigImporter.cs b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperConfigImporter.cs
new file mode 100644
index 0000000..dc9e596
--- /dev/null
+++ b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperConfigImporter.cs
@@ -0,0 +1,14 @@
+using System;
+using System.IO;
+using System.Xml;
+using System.Collections.Generic;
+using UnityEditor;
+using UnityEngine;
+
+namespace YooAsset.Editor
+{
+ public class AssetBundleGrouperConfigImporter
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperConfigImporter.cs.meta b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperConfigImporter.cs.meta
new file mode 100644
index 0000000..8e0211e
--- /dev/null
+++ b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperConfigImporter.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f9a030381c5944145a285c3212153ceb
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperSetting.cs b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperSetting.cs
new file mode 100644
index 0000000..0ff2b8f
--- /dev/null
+++ b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperSetting.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+namespace YooAsset.Editor
+{
+ public class AssetBundleGrouperSetting : ScriptableObject
+ {
+ ///
+ /// 自动收集着色器
+ ///
+ public bool AutoCollectShaders = true;
+
+ ///
+ /// 自动收集的着色器资源包名称
+ ///
+ public string ShadersBundleName = "myshaders";
+
+ ///
+ /// 分组列表
+ ///
+ public List Groupers = new List();
+
+
+ ///
+ /// 获取打包收集的资源文件
+ ///
+ public List GetAllCollectAssets()
+ {
+ Dictionary result = new Dictionary(10000);
+ foreach (var grouper in Groupers)
+ {
+ var temper = grouper.GetAllCollectAssets();
+ foreach (var assetInfo in temper)
+ {
+ if (result.ContainsKey(assetInfo.AssetPath) == false)
+ {
+ result.Add(assetInfo.AssetPath, assetInfo);
+ }
+ else
+ {
+ throw new Exception($"The collecting asset file is existed : {assetInfo.AssetPath}");
+ }
+ }
+ }
+ return result.Values.ToList();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperSetting.cs.meta b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperSetting.cs.meta
new file mode 100644
index 0000000..6ffa4bc
--- /dev/null
+++ b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperSetting.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 185f6993d5150494d98da50e26cb1c25
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperSettingData.cs b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperSettingData.cs
new file mode 100644
index 0000000..a367ff9
--- /dev/null
+++ b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperSettingData.cs
@@ -0,0 +1,267 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEditor;
+
+namespace YooAsset.Editor
+{
+ public class AssetBundleGrouperSettingData
+ {
+ private static readonly Dictionary _cachePackRuleTypes = new Dictionary();
+ private static readonly Dictionary _cachePackRuleInstance = new Dictionary();
+
+ private static readonly Dictionary _cacheFilterRuleTypes = new Dictionary();
+ private static readonly Dictionary _cacheFilterRuleInstance = new Dictionary();
+
+
+ private static AssetBundleGrouperSetting _setting = null;
+ public static AssetBundleGrouperSetting Setting
+ {
+ get
+ {
+ if (_setting == null)
+ LoadSettingData();
+ return _setting;
+ }
+ }
+
+ public static List GetPackRuleNames()
+ {
+ if (_setting == null)
+ LoadSettingData();
+
+ List names = new List();
+ foreach (var pair in _cachePackRuleTypes)
+ {
+ names.Add(pair.Key);
+ }
+ return names;
+ }
+ public static List GetFilterRuleNames()
+ {
+ if (_setting == null)
+ LoadSettingData();
+
+ List names = new List();
+ foreach (var pair in _cacheFilterRuleTypes)
+ {
+ names.Add(pair.Key);
+ }
+ return names;
+ }
+ public static bool HasPackRuleName(string ruleName)
+ {
+ foreach (var pair in _cachePackRuleTypes)
+ {
+ if (pair.Key == ruleName)
+ return true;
+ }
+ return false;
+ }
+ public static bool HasFilterRuleName(string ruleName)
+ {
+ foreach (var pair in _cacheFilterRuleTypes)
+ {
+ if (pair.Key == ruleName)
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// 加载配置文件
+ ///
+ private static void LoadSettingData()
+ {
+ // 加载配置文件
+ _setting = AssetDatabase.LoadAssetAtPath(EditorDefine.AssetBundleGrouperSettingFilePath);
+ if (_setting == null)
+ {
+ Debug.LogWarning($"Create new {nameof(AssetBundleGrouperSetting)}.asset : {EditorDefine.AssetBundleGrouperSettingFilePath}");
+ _setting = ScriptableObject.CreateInstance();
+ EditorTools.CreateFileDirectory(EditorDefine.AssetBundleGrouperSettingFilePath);
+ AssetDatabase.CreateAsset(Setting, EditorDefine.AssetBundleGrouperSettingFilePath);
+ AssetDatabase.SaveAssets();
+ AssetDatabase.Refresh();
+ }
+ else
+ {
+ Debug.Log($"Load {nameof(AssetBundleGrouperSetting)}.asset ok");
+ }
+
+ // IPackRule
+ {
+ // 清空缓存集合
+ _cachePackRuleTypes.Clear();
+ _cachePackRuleInstance.Clear();
+
+ // 获取所有类型
+ List types = new List(100)
+ {
+ typeof(PackSeparately),
+ typeof(PackDirectory),
+ typeof(PackCollector),
+ typeof(PackGrouper),
+ typeof(PackRawFile),
+ };
+ var customTypes = AssemblyUtility.GetAssignableTypes(AssemblyUtility.UnityDefaultAssemblyEditorName, typeof(IPackRule));
+ types.AddRange(customTypes);
+ for (int i = 0; i < types.Count; i++)
+ {
+ Type type = types[i];
+ if (_cachePackRuleTypes.ContainsKey(type.Name) == false)
+ _cachePackRuleTypes.Add(type.Name, type);
+ }
+ }
+
+ // IFilterRule
+ {
+ // 清空缓存集合
+ _cacheFilterRuleTypes.Clear();
+ _cacheFilterRuleInstance.Clear();
+
+ // 获取所有类型
+ List types = new List(100)
+ {
+ typeof(CollectAll),
+ typeof(CollectScene),
+ typeof(CollectPrefab),
+ typeof(CollectSprite)
+ };
+ var customTypes = AssemblyUtility.GetAssignableTypes(AssemblyUtility.UnityDefaultAssemblyEditorName, typeof(IFilterRule));
+ types.AddRange(customTypes);
+ for (int i = 0; i < types.Count; i++)
+ {
+ Type type = types[i];
+ if (_cacheFilterRuleTypes.ContainsKey(type.Name) == false)
+ _cacheFilterRuleTypes.Add(type.Name, type);
+ }
+ }
+ }
+
+ ///
+ /// 存储文件
+ ///
+ public static void SaveFile()
+ {
+ if (Setting != null)
+ {
+ EditorUtility.SetDirty(Setting);
+ AssetDatabase.SaveAssets();
+ }
+ }
+
+ ///
+ /// 清空所有数据
+ ///
+ public static void ClearAll()
+ {
+ Setting.AutoCollectShaders = false;
+ Setting.ShadersBundleName = string.Empty;
+ Setting.Groupers.Clear();
+ SaveFile();
+ }
+
+ // 实例类相关
+ public static IPackRule GetPackRuleInstance(string ruleName)
+ {
+ if (_cachePackRuleInstance.TryGetValue(ruleName, out IPackRule instance))
+ return instance;
+
+ // 如果不存在创建类的实例
+ if (_cachePackRuleTypes.TryGetValue(ruleName, out Type type))
+ {
+ instance = (IPackRule)Activator.CreateInstance(type);
+ _cachePackRuleInstance.Add(ruleName, instance);
+ return instance;
+ }
+ else
+ {
+ throw new Exception($"{nameof(IPackRule)}类型无效:{ruleName}");
+ }
+ }
+ public static IFilterRule GetFilterRuleInstance(string ruleName)
+ {
+ if (_cacheFilterRuleInstance.TryGetValue(ruleName, out IFilterRule instance))
+ return instance;
+
+ // 如果不存在创建类的实例
+ if (_cacheFilterRuleTypes.TryGetValue(ruleName, out Type type))
+ {
+ instance = (IFilterRule)Activator.CreateInstance(type);
+ _cacheFilterRuleInstance.Add(ruleName, instance);
+ return instance;
+ }
+ else
+ {
+ throw new Exception($"{nameof(IFilterRule)}类型无效:{ruleName}");
+ }
+ }
+
+ // 着色器编辑相关
+ public static void ModifyShader(bool isCollectAllShaders, string shadersBundleName)
+ {
+ if (string.IsNullOrEmpty(shadersBundleName))
+ return;
+ Setting.AutoCollectShaders = isCollectAllShaders;
+ Setting.ShadersBundleName = shadersBundleName;
+ SaveFile();
+ }
+
+ // 资源分组编辑相关
+ public static void CreateGrouper(string grouperName, string grouperDesc, string assetTags, bool saveFile = true)
+ {
+ AssetBundleGrouper grouper = new AssetBundleGrouper();
+ grouper.GrouperName = grouperName;
+ grouper.GrouperDesc = grouperDesc;
+ grouper.AssetTags = assetTags;
+ Setting.Groupers.Add(grouper);
+
+ if (saveFile)
+ SaveFile();
+ }
+ public static void RemoveGrouper(AssetBundleGrouper grouper)
+ {
+ if (Setting.Groupers.Remove(grouper))
+ {
+ SaveFile();
+ }
+ }
+ public static void ModifyGrouper(AssetBundleGrouper grouper)
+ {
+ if (grouper != null)
+ {
+ SaveFile();
+ }
+ }
+
+ // 资源收集器编辑相关
+ public static void CreateCollector(AssetBundleGrouper grouper, string collectPath, string packRuleName, string filterRuleName, bool notWriteToAssetList, bool saveFile = true)
+ {
+ AssetBundleCollector collector = new AssetBundleCollector();
+ collector.CollectPath = collectPath;
+ collector.PackRuleName = packRuleName;
+ collector.FilterRuleName = filterRuleName;
+ collector.NotWriteToAssetList = notWriteToAssetList;
+ grouper.Collectors.Add(collector);
+
+ if (saveFile)
+ SaveFile();
+ }
+ public static void RemoveCollector(AssetBundleGrouper grouper, AssetBundleCollector collector)
+ {
+ if (grouper.Collectors.Remove(collector))
+ {
+ SaveFile();
+ }
+ }
+ public static void ModifyCollector(AssetBundleGrouper grouper, AssetBundleCollector collector)
+ {
+ if (grouper != null && collector != null)
+ {
+ SaveFile();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperSettingData.cs.meta b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperSettingData.cs.meta
new file mode 100644
index 0000000..d003af2
--- /dev/null
+++ b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperSettingData.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 2fa91f25d246411459816310b09480a5
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperWindow.cs b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperWindow.cs
new file mode 100644
index 0000000..51fea61
--- /dev/null
+++ b/Assets/YooAsset/Editor/AssetBundleGrouper/AssetBundleGrouperWindow.cs
@@ -0,0 +1,394 @@
+#if UNITY_2019_4_OR_NEWER
+using System.IO;
+using System.Linq;
+using System.Collections.Generic;
+using UnityEditor;
+using UnityEngine;
+using UnityEditor.UIElements;
+using UnityEngine.UIElements;
+
+namespace YooAsset.Editor
+{
+ public class AssetBundleGrouperWindow : EditorWindow
+ {
+ [MenuItem("YooAsset/AssetBundle Grouper", false, 100)]
+ public static void ShowExample()
+ {
+ AssetBundleGrouperWindow window = GetWindow();
+ window.titleContent = new GUIContent("资源包分组工具");
+ window.minSize = new Vector2(800, 600);
+ }
+
+ private List _packRuleList;
+ private List _filterRuleList;
+ private ListView _grouperListView;
+ private ListView _collectorListView;
+ private Toggle _autoCollectShaderToogle;
+ private TextField _shaderBundleNameTxt;
+ private TextField _grouperNameTxt;
+ private TextField _grouperDescTxt;
+ private TextField _grouperAssetTagsTxt;
+ private VisualElement _rightContainer;
+
+ public void CreateGUI()
+ {
+ VisualElement root = this.rootVisualElement;
+
+ _packRuleList = AssetBundleGrouperSettingData.GetPackRuleNames();
+ _filterRuleList = AssetBundleGrouperSettingData.GetFilterRuleNames();
+
+ // 加载布局文件
+ string rootPath = EditorTools.GetYooAssetPath();
+ string uxml = $"{rootPath}/Editor/AssetBundleGrouper/{nameof(AssetBundleGrouperWindow)}.uxml";
+ var visualAsset = AssetDatabase.LoadAssetAtPath(uxml);
+ if (visualAsset == null)
+ {
+ Debug.LogError($"Not found {nameof(AssetBundleGrouperWindow)}.uxml : {uxml}");
+ return;
+ }
+ visualAsset.CloneTree(root);
+
+ try
+ {
+ // 着色器相关
+ _autoCollectShaderToogle = root.Q("AutoCollectShader");
+ _autoCollectShaderToogle.SetValueWithoutNotify(AssetBundleGrouperSettingData.Setting.AutoCollectShaders);
+ _autoCollectShaderToogle.RegisterValueChangedCallback(evt =>
+ {
+ AssetBundleGrouperSettingData.ModifyShader(evt.newValue, _shaderBundleNameTxt.value);
+ });
+
+ _shaderBundleNameTxt = root.Q("ShaderBundleName");
+ _shaderBundleNameTxt.SetValueWithoutNotify(AssetBundleGrouperSettingData.Setting.ShadersBundleName);
+ _shaderBundleNameTxt.RegisterValueChangedCallback(evt =>
+ {
+ AssetBundleGrouperSettingData.ModifyShader(_autoCollectShaderToogle.value, evt.newValue);
+ });
+
+ // 分组列表相关
+ _grouperListView = root.Q("GrouperListView");
+ _grouperListView.makeItem = MakeGrouperListViewItem;
+ _grouperListView.bindItem = BindGrouperListViewItem;
+#if UNITY_2020_1_OR_NEWER
+ _grouperListView.onSelectionChange += GrouperListView_onSelectionChange;
+#else
+ _grouperListView.onSelectionChanged += GrouperListView_onSelectionChange;
+#endif
+
+ // 分组添加删除按钮
+ var grouperAddContainer = root.Q("GrouperAddContainer");
+ {
+ var addBtn = grouperAddContainer.Q