/// <summary>
        /// 检测配置错误
        /// </summary>
        public void CheckConfigError()
        {
            if (AssetDatabase.LoadAssetAtPath <UnityEngine.Object>(CollectPath) == null)
            {
                throw new Exception($"Invalid collect path : {CollectPath}");
            }

            if (CollectorType == ECollectorType.None)
            {
                throw new Exception($"{nameof(ECollectorType)}.{ECollectorType.None} is invalid in collector : {CollectPath}");
            }

            if (AssetBundleCollectorSettingData.HasPackRuleName(PackRuleName) == false)
            {
                throw new Exception($"Invalid {nameof(IPackRule)} class type : {PackRuleName} in collector : {CollectPath}");
            }

            if (AssetBundleCollectorSettingData.HasFilterRuleName(FilterRuleName) == false)
            {
                throw new Exception($"Invalid {nameof(IFilterRule)} class type : {FilterRuleName} in collector : {CollectPath}");
            }

            if (AssetBundleCollectorSettingData.HasAddressRuleName(AddressRuleName) == false)
            {
                throw new Exception($"Invalid {nameof(IAddressRule)} class type : {AddressRuleName} in collector : {CollectPath}");
            }
        }
        /// <summary>
        /// 收集器是否有效
        /// </summary>
        public bool IsValid()
        {
            if (AssetDatabase.LoadAssetAtPath <UnityEngine.Object>(CollectPath) == null)
            {
                return(false);
            }

            if (CollectorType == ECollectorType.None)
            {
                return(false);
            }

            if (AssetBundleCollectorSettingData.HasAddressRuleName(AddressRuleName) == false)
            {
                return(false);
            }

            if (AssetBundleCollectorSettingData.HasPackRuleName(PackRuleName) == false)
            {
                return(false);
            }

            if (AssetBundleCollectorSettingData.HasFilterRuleName(FilterRuleName) == false)
            {
                return(false);
            }

            return(true);
        }
        public void OnDestroy()
        {
            // 注意:清空所有撤销操作
            Undo.ClearAll();

            if (AssetBundleCollectorSettingData.IsDirty)
            {
                AssetBundleCollectorSettingData.SaveFile();
            }
        }
        private string GetAddress(AssetBundleCollectorGroup group, string assetPath)
        {
            if (CollectorType != ECollectorType.MainAssetCollector)
            {
                return(string.Empty);
            }

            IAddressRule addressRuleInstance = AssetBundleCollectorSettingData.GetAddressRuleInstance(AddressRuleName);
            string       adressValue         = addressRuleInstance.GetAssetAddress(new AddressRuleData(assetPath, CollectPath, group.GroupName));

            return(adressValue);
        }
        private void AddCollectorBtn_clicked()
        {
            var selectGroup = _groupListView.selectedItem as AssetBundleCollectorGroup;

            if (selectGroup == null)
            {
                return;
            }

            Undo.RecordObject(AssetBundleCollectorSettingData.Setting, "YooAsset.AssetBundleCollectorWindow AddCollector");
            AssetBundleCollectorSettingData.CreateCollector(selectGroup, string.Empty);
            FillCollectorViewData();
        }
        private void RemoveGroupBtn_clicked()
        {
            var selectGroup = _groupListView.selectedItem as AssetBundleCollectorGroup;

            if (selectGroup == null)
            {
                return;
            }

            Undo.RecordObject(AssetBundleCollectorSettingData.Setting, "YooAsset.AssetBundleCollectorWindow RemoveGroup");
            AssetBundleCollectorSettingData.RemoveGroup(selectGroup);
            FillGroupViewData();
        }
        private void RefreshFoldout(Foldout foldout, AssetBundleCollectorGroup group, AssetBundleCollector collector)
        {
            // 清空旧元素
            foldout.Clear();

            if (collector.IsValid() == false)
            {
                Debug.LogWarning($"The collector is invalid : {collector.CollectPath} in group : {group.GroupName}");
                return;
            }

            if (collector.CollectorType == ECollectorType.MainAssetCollector || collector.CollectorType == ECollectorType.StaticAssetCollector)
            {
                List <CollectAssetInfo> collectAssetInfos = null;

                try
                {
                    collectAssetInfos = collector.GetAllCollectAssets(group);
                }
                catch (System.Exception e)
                {
                    Debug.LogError(e.ToString());
                }

                if (collectAssetInfos != null)
                {
                    foreach (var collectAssetInfo in collectAssetInfos)
                    {
                        VisualElement elementRow = new VisualElement();
                        elementRow.style.flexDirection = FlexDirection.Row;
                        foldout.Add(elementRow);

                        string showInfo = collectAssetInfo.AssetPath;
                        if (_enableAddressableToogle.value)
                        {
                            IAddressRule    instance     = AssetBundleCollectorSettingData.GetAddressRuleInstance(collector.AddressRuleName);
                            AddressRuleData ruleData     = new AddressRuleData(collectAssetInfo.AssetPath, collector.CollectPath, group.GroupName);
                            string          addressValue = instance.GetAssetAddress(ruleData);
                            showInfo = $"[{addressValue}] {showInfo}";
                        }

                        var label = new Label();
                        label.text             = showInfo;
                        label.style.width      = 300;
                        label.style.marginLeft = 0;
                        label.style.flexGrow   = 1;
                        elementRow.Add(label);
                    }
                }
            }
        }
        private bool IsCollectAsset(string assetPath)
        {
            // 如果收集全路径着色器
            if (AssetBundleCollectorSettingData.Setting.AutoCollectShaders)
            {
                Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
                if (assetType == typeof(UnityEngine.Shader))
                {
                    return(true);
                }
            }

            // 根据规则设置过滤资源文件
            IFilterRule filterRuleInstance = AssetBundleCollectorSettingData.GetFilterRuleInstance(FilterRuleName);

            return(filterRuleInstance.IsCollectAsset(new FilterRuleData(assetPath)));
        }
        private string GetBundleName(AssetBundleCollectorGroup group, string assetPath)
        {
            // 如果自动收集所有的着色器
            if (AssetBundleCollectorSettingData.Setting.AutoCollectShaders)
            {
                System.Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
                if (assetType == typeof(UnityEngine.Shader))
                {
                    string bundleName = AssetBundleCollectorSettingData.Setting.ShadersBundleName;
                    return(EditorTools.GetRegularPath(bundleName).ToLower());
                }
            }

            // 根据规则设置获取资源包名称
            {
                IPackRule packRuleInstance = AssetBundleCollectorSettingData.GetPackRuleInstance(PackRuleName);
                string    bundleName       = packRuleInstance.GetBundleName(new PackRuleData(assetPath, CollectPath, group.GroupName));
                return(EditorTools.GetRegularPath(bundleName).ToLower());
            }
        }
        /// <summary>
        /// 导入XML配置表
        /// </summary>
        public static void ImportXmlConfig(string filePath)
        {
            if (File.Exists(filePath) == false)
            {
                throw new FileNotFoundException(filePath);
            }

            if (Path.GetExtension(filePath) != ".xml")
            {
                throw new Exception($"Only support xml : {filePath}");
            }

            // 加载配置文件
            XmlDocument xml = new XmlDocument();

            xml.Load(filePath);
            XmlElement root = xml.DocumentElement;

            // 读取配置版本
            string configVersion = root.GetAttribute(XmlVersion);

            if (configVersion != ConfigVersion)
            {
                throw new Exception($"The config version is invalid : {configVersion}");
            }

            // 读取公共配置
            bool   enableAddressable  = false;
            bool   autoCollectShaders = false;
            string shaderBundleName   = string.Empty;
            var    commonNodeList     = root.GetElementsByTagName(XmlCommon);

            if (commonNodeList.Count > 0)
            {
                XmlElement commonElement = commonNodeList[0] as XmlElement;
                if (commonElement.HasAttribute(XmlEnableAddressable) == false)
                {
                    throw new Exception($"Not found attribute {XmlEnableAddressable} in {XmlCommon}");
                }
                if (commonElement.HasAttribute(XmlAutoCollectShader) == false)
                {
                    throw new Exception($"Not found attribute {XmlAutoCollectShader} in {XmlCommon}");
                }
                if (commonElement.HasAttribute(XmlShaderBundleName) == false)
                {
                    throw new Exception($"Not found attribute {XmlShaderBundleName} in {XmlCommon}");
                }

                enableAddressable  = commonElement.GetAttribute(XmlEnableAddressable) == "True" ? true : false;
                autoCollectShaders = commonElement.GetAttribute(XmlAutoCollectShader) == "True" ? true : false;
                shaderBundleName   = commonElement.GetAttribute(XmlShaderBundleName);
            }

            // 读取分组配置
            List <AssetBundleCollectorGroup> groupTemper = new List <AssetBundleCollectorGroup>();
            var groupNodeList = root.GetElementsByTagName(XmlGroup);

            foreach (var groupNode in groupNodeList)
            {
                XmlElement groupElement = groupNode as XmlElement;
                if (groupElement.HasAttribute(XmlGroupName) == false)
                {
                    throw new Exception($"Not found attribute {XmlGroupName} in {XmlGroup}");
                }
                if (groupElement.HasAttribute(XmlGroupDesc) == false)
                {
                    throw new Exception($"Not found attribute {XmlGroupDesc} in {XmlGroup}");
                }
                if (groupElement.HasAttribute(XmlAssetTags) == false)
                {
                    throw new Exception($"Not found attribute {XmlAssetTags} in {XmlGroup}");
                }

                AssetBundleCollectorGroup group = new AssetBundleCollectorGroup();
                group.GroupName = groupElement.GetAttribute(XmlGroupName);
                group.GroupDesc = groupElement.GetAttribute(XmlGroupDesc);
                group.AssetTags = groupElement.GetAttribute(XmlAssetTags);
                groupTemper.Add(group);

                // 读取收集器配置
                var collectorNodeList = groupElement.GetElementsByTagName(XmlCollector);
                foreach (var collectorNode in collectorNodeList)
                {
                    XmlElement collectorElement = collectorNode as XmlElement;
                    if (collectorElement.HasAttribute(XmlCollectPath) == false)
                    {
                        throw new Exception($"Not found attribute {XmlCollectPath} in {XmlCollector}");
                    }
                    if (collectorElement.HasAttribute(XmlCollectorType) == false)
                    {
                        throw new Exception($"Not found attribute {XmlCollectorType} in {XmlCollector}");
                    }
                    if (collectorElement.HasAttribute(XmlAddressRule) == false)
                    {
                        throw new Exception($"Not found attribute {XmlAddressRule} in {XmlCollector}");
                    }
                    if (collectorElement.HasAttribute(XmlPackRule) == false)
                    {
                        throw new Exception($"Not found attribute {XmlPackRule} in {XmlCollector}");
                    }
                    if (collectorElement.HasAttribute(XmlFilterRule) == false)
                    {
                        throw new Exception($"Not found attribute {XmlFilterRule} in {XmlCollector}");
                    }
                    if (collectorElement.HasAttribute(XmlAssetTags) == false)
                    {
                        throw new Exception($"Not found attribute {XmlAssetTags} in {XmlCollector}");
                    }

                    AssetBundleCollector collector = new AssetBundleCollector();
                    collector.CollectPath     = collectorElement.GetAttribute(XmlCollectPath);
                    collector.CollectorType   = StringUtility.NameToEnum <ECollectorType>(collectorElement.GetAttribute(XmlCollectorType));
                    collector.AddressRuleName = collectorElement.GetAttribute(XmlAddressRule);
                    collector.PackRuleName    = collectorElement.GetAttribute(XmlPackRule);
                    collector.FilterRuleName  = collectorElement.GetAttribute(XmlFilterRule);
                    collector.AssetTags       = collectorElement.GetAttribute(XmlAssetTags);;
                    group.Collectors.Add(collector);
                }
            }

            // 保存配置数据
            AssetBundleCollectorSettingData.ClearAll();
            AssetBundleCollectorSettingData.Setting.EnableAddressable  = enableAddressable;
            AssetBundleCollectorSettingData.Setting.AutoCollectShaders = autoCollectShaders;
            AssetBundleCollectorSettingData.Setting.ShadersBundleName  = shaderBundleName;
            AssetBundleCollectorSettingData.Setting.Groups.AddRange(groupTemper);
            AssetBundleCollectorSettingData.SaveFile();
            Debug.Log($"导入配置完毕!");
        }
        private void BindCollectorListViewItem(VisualElement element, int index)
        {
            var selectGroup = _groupListView.selectedItem as AssetBundleCollectorGroup;

            if (selectGroup == null)
            {
                return;
            }

            var collector     = selectGroup.Collectors[index];
            var collectObject = AssetDatabase.LoadAssetAtPath <UnityEngine.Object>(collector.CollectPath);

            if (collectObject != null)
            {
                collectObject.name = collector.CollectPath;
            }

            // Foldout
            var foldout = element.Q <Foldout>("Foldout1");

            foldout.RegisterValueChangedCallback(evt =>
            {
                if (evt.newValue)
                {
                    RefreshFoldout(foldout, selectGroup, collector);
                }
                else
                {
                    foldout.Clear();
                }
            });

            // Remove Button
            var removeBtn = element.Q <Button>("Button1");

            removeBtn.clicked += () =>
            {
                RemoveCollectorBtn_clicked(collector);
            };

            // Collector Path
            var objectField1 = element.Q <ObjectField>("ObjectField1");

            objectField1.SetValueWithoutNotify(collectObject);
            objectField1.RegisterValueChangedCallback(evt =>
            {
                collector.CollectPath   = AssetDatabase.GetAssetPath(evt.newValue);
                objectField1.value.name = collector.CollectPath;
                AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector);
                if (foldout.value)
                {
                    RefreshFoldout(foldout, selectGroup, collector);
                }
            });

            // Collector Type
            var popupField0 = element.Q <PopupField <string> >("PopupField0");

            popupField0.index = GetCollectorTypeIndex(collector.CollectorType.ToString());
            popupField0.RegisterValueChangedCallback(evt =>
            {
                collector.CollectorType = StringUtility.NameToEnum <ECollectorType>(evt.newValue);
                AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector);
                if (foldout.value)
                {
                    RefreshFoldout(foldout, selectGroup, collector);
                }
            });

            // Address Rule
            var popupField1 = element.Q <PopupField <string> >("PopupField1");

            if (popupField1 != null)
            {
                popupField1.index = GetAddressRuleIndex(collector.AddressRuleName);
                popupField1.RegisterValueChangedCallback(evt =>
                {
                    collector.AddressRuleName = evt.newValue;
                    AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector);
                    if (foldout.value)
                    {
                        RefreshFoldout(foldout, selectGroup, collector);
                    }
                });
            }

            // Pack Rule
            var popupField2 = element.Q <PopupField <string> >("PopupField2");

            popupField2.index = GetPackRuleIndex(collector.PackRuleName);
            popupField2.RegisterValueChangedCallback(evt =>
            {
                collector.PackRuleName = evt.newValue;
                AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector);
                if (foldout.value)
                {
                    RefreshFoldout(foldout, selectGroup, collector);
                }
            });

            // Filter Rule
            var popupField3 = element.Q <PopupField <string> >("PopupField3");

            popupField3.index = GetFilterRuleIndex(collector.FilterRuleName);
            popupField3.RegisterValueChangedCallback(evt =>
            {
                collector.FilterRuleName = evt.newValue;
                AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector);
                if (foldout.value)
                {
                    RefreshFoldout(foldout, selectGroup, collector);
                }
            });

            // Tags
            var textFiled1 = element.Q <TextField>("TextField1");

            textFiled1.SetValueWithoutNotify(collector.AssetTags);
            textFiled1.RegisterValueChangedCallback(evt =>
            {
                collector.AssetTags = evt.newValue;
                AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector);
            });
        }
        public void CreateGUI()
        {
            Undo.undoRedoPerformed -= RefreshWindow;
            Undo.undoRedoPerformed += RefreshWindow;

            try
            {
                _collectorTypeList = new List <string>()
                {
                    $"{nameof(ECollectorType.MainAssetCollector)}",
                    $"{nameof(ECollectorType.StaticAssetCollector)}",
                    $"{nameof(ECollectorType.DependAssetCollector)}"
                };
                _addressRuleList = AssetBundleCollectorSettingData.GetAddressRuleNames();
                _packRuleList    = AssetBundleCollectorSettingData.GetPackRuleNames();
                _filterRuleList  = AssetBundleCollectorSettingData.GetFilterRuleNames();

                VisualElement root = this.rootVisualElement;

                // 加载布局文件
                var visualAsset = EditorHelper.LoadWindowUXML <AssetBundleCollectorWindow>();
                if (visualAsset == null)
                {
                    return;
                }

                visualAsset.CloneTree(root);

                // 导入导出按钮
                var exportBtn = root.Q <Button>("ExportButton");
                exportBtn.clicked += ExportBtn_clicked;
                var importBtn = root.Q <Button>("ImportButton");
                importBtn.clicked += ImportBtn_clicked;

                // 公共设置相关
                _enableAddressableToogle = root.Q <Toggle>("EnableAddressable");
                _enableAddressableToogle.RegisterValueChangedCallback(evt =>
                {
                    AssetBundleCollectorSettingData.ModifyAddressable(evt.newValue);
                });
                _autoCollectShaderToogle = root.Q <Toggle>("AutoCollectShader");
                _autoCollectShaderToogle.RegisterValueChangedCallback(evt =>
                {
                    AssetBundleCollectorSettingData.ModifyShader(evt.newValue, _shaderBundleNameTxt.value);
                    _shaderBundleNameTxt.SetEnabled(evt.newValue);
                });
                _shaderBundleNameTxt = root.Q <TextField>("ShaderBundleName");
                _shaderBundleNameTxt.RegisterValueChangedCallback(evt =>
                {
                    AssetBundleCollectorSettingData.ModifyShader(_autoCollectShaderToogle.value, evt.newValue);
                });

                // 分组列表相关
                _groupListView          = root.Q <ListView>("GroupListView");
                _groupListView.makeItem = MakeGroupListViewItem;
                _groupListView.bindItem = BindGroupListViewItem;
#if UNITY_2020_1_OR_NEWER
                _groupListView.onSelectionChange += GroupListView_onSelectionChange;
#else
                _groupListView.onSelectionChanged += GroupListView_onSelectionChange;
#endif

                // 分组添加删除按钮
                var groupAddContainer = root.Q("GroupAddContainer");
                {
                    var addBtn = groupAddContainer.Q <Button>("AddBtn");
                    addBtn.clicked += AddGroupBtn_clicked;
                    var removeBtn = groupAddContainer.Q <Button>("RemoveBtn");
                    removeBtn.clicked += RemoveGroupBtn_clicked;
                }

                // 分组容器
                _groupContainer = root.Q("GroupContainer");

                // 分组名称
                _groupNameTxt = root.Q <TextField>("GroupName");
                _groupNameTxt.RegisterValueChangedCallback(evt =>
                {
                    var selectGroup = _groupListView.selectedItem as AssetBundleCollectorGroup;
                    if (selectGroup != null)
                    {
                        selectGroup.GroupName = evt.newValue;
                        AssetBundleCollectorSettingData.ModifyGroup(selectGroup);
                    }
                });

                // 分组备注
                _groupDescTxt = root.Q <TextField>("GroupDesc");
                _groupDescTxt.RegisterValueChangedCallback(evt =>
                {
                    var selectGroup = _groupListView.selectedItem as AssetBundleCollectorGroup;
                    if (selectGroup != null)
                    {
                        selectGroup.GroupDesc = evt.newValue;
                        AssetBundleCollectorSettingData.ModifyGroup(selectGroup);
                    }
                });

                // 分组的资源标签
                _groupAssetTagsTxt = root.Q <TextField>("GroupAssetTags");
                _groupAssetTagsTxt.RegisterValueChangedCallback(evt =>
                {
                    var selectGroup = _groupListView.selectedItem as AssetBundleCollectorGroup;
                    if (selectGroup != null)
                    {
                        selectGroup.AssetTags = evt.newValue;
                        AssetBundleCollectorSettingData.ModifyGroup(selectGroup);
                    }
                });

                // 收集列表相关
                _collectorScrollView = root.Q <ScrollView>("CollectorScrollView");
                _collectorScrollView.style.height = new Length(100, LengthUnit.Percent);
                _collectorScrollView.viewDataKey  = "scrollView";

                // 收集器创建按钮
                var collectorAddContainer = root.Q("CollectorAddContainer");
                {
                    var addBtn = collectorAddContainer.Q <Button>("AddBtn");
                    addBtn.clicked += AddCollectorBtn_clicked;
                }

                // 刷新窗体
                RefreshWindow();
            }
            catch (System.Exception e)
            {
                Debug.LogError(e.ToString());
            }
        }
 private void AddGroupBtn_clicked()
 {
     Undo.RecordObject(AssetBundleCollectorSettingData.Setting, "YooAsset.AssetBundleCollectorWindow AddGroup");
     AssetBundleCollectorSettingData.CreateGroup("Default Group");
     FillGroupViewData();
 }