/// <summary>
        /// 清理所有材质球的冗余属性
        /// </summary>
        public static void ClearMaterialUnusedProperty(List <string> searchDirectorys)
        {
            if (searchDirectorys.Count == 0)
            {
                throw new Exception("路径列表不能为空!");
            }

            // 获取所有资源列表
            int checkCount   = 0;
            int removedCount = 0;

            string[] findAssets = EditorTools.FindAssets(EAssetSearchType.Material, searchDirectorys.ToArray());
            foreach (string assetPath in findAssets)
            {
                Material mat = AssetDatabase.LoadAssetAtPath <Material>(assetPath);
                if (ClearMaterialUnusedProperty(mat))
                {
                    removedCount++;
                    Debug.LogWarning($"材质球已被处理:{assetPath}");
                }
                EditorTools.DisplayProgressBar("清理冗余的材质球", ++checkCount, findAssets.Length);
            }
            EditorTools.ClearProgressBar();

            if (removedCount == 0)
            {
                Debug.Log($"没有发现冗余的材质球");
            }
            else
            {
                AssetDatabase.SaveAssets();
            }
        }
        /// <summary>
        /// 检测所有损坏的预制体文件
        /// </summary>
        public static void CheckCorruptionPrefab(List <string> searchDirectorys)
        {
            if (searchDirectorys.Count == 0)
            {
                throw new Exception("路径列表不能为空!");
            }

            // 获取所有资源列表
            int checkCount   = 0;
            int invalidCount = 0;

            string[] findAssets = EditorTools.FindAssets(EAssetSearchType.Prefab, searchDirectorys.ToArray());
            foreach (string assetPath in findAssets)
            {
                UnityEngine.Object prefab = AssetDatabase.LoadAssetAtPath(assetPath, typeof(UnityEngine.Object));
                if (prefab == null)
                {
                    invalidCount++;
                    Debug.LogError($"发现损坏预制件:{assetPath}");
                }
                EditorTools.DisplayProgressBar("检测预制件文件是否损坏", ++checkCount, findAssets.Length);
            }
            EditorTools.ClearProgressBar();

            if (invalidCount == 0)
            {
                Debug.Log($"没有发现损坏预制件");
            }
        }
        /// <summary>
        /// 检测所有动画控制器的冗余状态
        /// </summary>
        public static void FindRedundantAnimationState(List <string> searchDirectorys)
        {
            if (searchDirectorys.Count == 0)
            {
                throw new Exception("路径列表不能为空!");
            }

            // 获取所有资源列表
            int checkCount = 0;
            int findCount  = 0;

            string[] findAssets = EditorTools.FindAssets(EAssetSearchType.RuntimeAnimatorController, searchDirectorys.ToArray());
            foreach (string assetPath in findAssets)
            {
                AnimatorController animator = AssetDatabase.LoadAssetAtPath <AnimatorController>(assetPath);
                if (FindRedundantAnimationState(animator))
                {
                    findCount++;
                    Debug.LogWarning($"发现冗余的动画控制器:{assetPath}");
                }
                EditorTools.DisplayProgressBar("检测冗余的动画控制器", ++checkCount, findAssets.Length);
            }
            EditorTools.ClearProgressBar();

            if (findCount == 0)
            {
                Debug.Log($"没有发现冗余的动画控制器");
            }
            else
            {
                AssetDatabase.SaveAssets();
            }
        }
Esempio n. 4
0
        /// <summary>
        /// 加密文件
        /// </summary>
        private List <string> EncryptFiles(AssetBundleBuilder.BuildParametersContext buildParameters, BuildMapContext buildMapContext)
        {
            var encryptionServices = buildParameters.Parameters.EncryptionServices;

            // 加密资源列表
            List <string> encryptList = new List <string>();

            // 如果没有设置加密类
            if (encryptionServices == null)
            {
                return(encryptList);
            }

            int progressValue = 0;

            foreach (var bundleInfo in buildMapContext.BundleInfos)
            {
                if (encryptionServices.Check(bundleInfo.BundleName))
                {
                    if (bundleInfo.IsRawFile)
                    {
                        UnityEngine.Debug.LogWarning($"Encryption not support raw file : {bundleInfo.BundleName}");
                        continue;
                    }

                    encryptList.Add(bundleInfo.BundleName);

                    // 注意:通过判断文件合法性,规避重复加密一个文件
                    string filePath = $"{buildParameters.PipelineOutputDirectory}/{bundleInfo.BundleName}";
                    byte[] fileData = File.ReadAllBytes(filePath);
                    if (EditorTools.CheckBundleFileValid(fileData))
                    {
                        byte[] bytes = encryptionServices.Encrypt(fileData);
                        File.WriteAllBytes(filePath, bytes);
                        BuildRunner.Log($"文件加密完成:{filePath}");
                    }
                }

                // 进度条
                EditorTools.DisplayProgressBar("加密资源包", ++progressValue, buildMapContext.BundleInfos.Count);
            }
            EditorTools.ClearProgressBar();

            if (encryptList.Count == 0)
            {
                UnityEngine.Debug.LogWarning($"没有发现需要加密的文件!");
            }
            return(encryptList);
        }
        private static void CollectVariants(List <Material> materials)
        {
            Camera camera = Camera.main;

            if (camera == null)
            {
                throw new System.Exception("Not found main camera.");
            }

            // 设置主相机
            float aspect         = camera.aspect;
            int   totalMaterials = materials.Count;
            float height         = Mathf.Sqrt(totalMaterials / aspect) + 1;
            float width          = Mathf.Sqrt(totalMaterials / aspect) * aspect + 1;
            float halfHeight     = Mathf.CeilToInt(height / 2f);
            float halfWidth      = Mathf.CeilToInt(width / 2f);

            camera.orthographic       = true;
            camera.orthographicSize   = halfHeight;
            camera.transform.position = new Vector3(0f, 0f, -10f);

            // 创建测试球体
            int xMax = (int)(width - 1);
            int x = 0, y = 0;
            int progressValue = 0;

            for (int i = 0; i < materials.Count; i++)
            {
                var material = materials[i];
                var position = new Vector3(x - halfWidth + 1f, y - halfHeight + 1f, 0f);
                CreateSphere(material, position, i);
                if (x == xMax)
                {
                    x = 0;
                    y++;
                }
                else
                {
                    x++;
                }
                EditorTools.DisplayProgressBar("测试所有材质球", ++progressValue, materials.Count);
            }
            EditorTools.ClearProgressBar();
        }
        /// <summary>
        /// 拷贝补丁文件到补丁包目录
        /// </summary>
        private void CopyPatchFiles(AssetBundleBuilder.BuildParametersContext buildParameters)
        {
            int    resourceVersion  = buildParameters.Parameters.BuildVersion;
            string packageDirectory = buildParameters.GetPackageDirectory();

            BuildRunner.Log($"开始拷贝补丁文件到补丁包目录:{packageDirectory}");

            // 拷贝Report文件
            {
                string reportFileName = YooAssetSettingsData.GetReportFileName(buildParameters.Parameters.BuildVersion);
                string sourcePath     = $"{buildParameters.PipelineOutputDirectory}/{reportFileName}";
                string destPath       = $"{packageDirectory}/{reportFileName}";
                EditorTools.CopyFile(sourcePath, destPath, true);
            }

            // 拷贝补丁清单文件
            {
                string sourcePath = $"{buildParameters.PipelineOutputDirectory}/{YooAssetSettingsData.GetPatchManifestFileName(resourceVersion)}";
                string destPath   = $"{packageDirectory}/{YooAssetSettingsData.GetPatchManifestFileName(resourceVersion)}";
                EditorTools.CopyFile(sourcePath, destPath, true);
            }

            // 拷贝补丁清单哈希文件
            {
                string sourcePath = $"{buildParameters.PipelineOutputDirectory}/{YooAssetSettingsData.GetPatchManifestHashFileName(resourceVersion)}";
                string destPath   = $"{packageDirectory}/{YooAssetSettingsData.GetPatchManifestHashFileName(resourceVersion)}";
                EditorTools.CopyFile(sourcePath, destPath, true);
            }

            // 拷贝静态版本文件
            {
                string sourcePath = $"{buildParameters.PipelineOutputDirectory}/{YooAssetSettings.VersionFileName}";
                string destPath   = $"{packageDirectory}/{YooAssetSettings.VersionFileName}";
                EditorTools.CopyFile(sourcePath, destPath, true);
            }

            // 拷贝UnityManifest序列化文件
            {
                string sourcePath = $"{buildParameters.PipelineOutputDirectory}/{YooAssetSettingsData.Setting.UnityManifestFileName}";
                string destPath   = $"{packageDirectory}/{YooAssetSettingsData.Setting.UnityManifestFileName}";
                EditorTools.CopyFile(sourcePath, destPath, true);
            }

            // 拷贝UnityManifest文本文件
            {
                string sourcePath = $"{buildParameters.PipelineOutputDirectory}/{YooAssetSettingsData.Setting.UnityManifestFileName}.manifest";
                string destPath   = $"{packageDirectory}/{YooAssetSettingsData.Setting.UnityManifestFileName}.manifest";
                EditorTools.CopyFile(sourcePath, destPath, true);
            }

            // 拷贝所有补丁文件
            int           progressValue       = 0;
            PatchManifest patchManifest       = AssetBundleBuilderHelper.LoadPatchManifestFile(buildParameters.PipelineOutputDirectory, buildParameters.Parameters.BuildVersion);
            int           patchFileTotalCount = patchManifest.BundleList.Count;

            foreach (var patchBundle in patchManifest.BundleList)
            {
                string sourcePath = $"{buildParameters.PipelineOutputDirectory}/{patchBundle.BundleName}";
                string destPath   = $"{packageDirectory}/{patchBundle.Hash}";
                EditorTools.CopyFile(sourcePath, destPath, true);
                EditorTools.DisplayProgressBar("拷贝补丁文件", ++progressValue, patchFileTotalCount);
            }
            EditorTools.ClearProgressBar();
        }
        private static List <Material> GetAllMaterials()
        {
            int           progressValue = 0;
            List <string> allAssets     = new List <string>(1000);

            // 获取所有打包的资源
            List <CollectAssetInfo> allCollectInfos = AssetBundleCollectorSettingData.Setting.GetAllCollectAssets(EBuildMode.DryRunBuild);
            List <string>           collectAssets   = allCollectInfos.Select(t => t.AssetPath).ToList();

            foreach (var assetPath in collectAssets)
            {
                string[] depends = AssetDatabase.GetDependencies(assetPath, true);
                foreach (var depend in depends)
                {
                    if (allAssets.Contains(depend) == false)
                    {
                        allAssets.Add(depend);
                    }
                }
                EditorTools.DisplayProgressBar("获取所有打包资源", ++progressValue, collectAssets.Count);
            }
            EditorTools.ClearProgressBar();

            // 搜集所有材质球
            progressValue = 0;
            var shaderDic = new Dictionary <Shader, List <Material> >(100);

            foreach (var assetPath in allAssets)
            {
                System.Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
                if (assetType == typeof(UnityEngine.Material))
                {
                    var material = AssetDatabase.LoadAssetAtPath <Material>(assetPath);
                    var shader   = material.shader;
                    if (shader == null)
                    {
                        continue;
                    }

                    if (shaderDic.ContainsKey(shader) == false)
                    {
                        shaderDic.Add(shader, new List <Material>());
                    }
                    if (shaderDic[shader].Contains(material) == false)
                    {
                        shaderDic[shader].Add(material);
                    }
                }
                EditorTools.DisplayProgressBar("搜集所有材质球", ++progressValue, allAssets.Count);
            }
            EditorTools.ClearProgressBar();

            // 返回结果
            var materials = new List <Material>(1000);

            foreach (var valuePair in shaderDic)
            {
                materials.AddRange(valuePair.Value);
            }
            return(materials);
        }
        /// <summary>
        /// 验证构建结果
        /// </summary>
        private void VerifyingBuildingResult(BuildContext context, AssetBundleManifest unityManifest)
        {
            var buildParameters = context.GetContextObject <AssetBundleBuilder.BuildParametersContext>();
            var buildMapContext = context.GetContextObject <BuildMapContext>();

            string[] buildedBundles = unityManifest.GetAllAssetBundles();

            // 1. 过滤掉原生Bundle
            List <BuildBundleInfo> expectBundles = new List <BuildBundleInfo>(buildedBundles.Length);

            foreach (var bundleInfo in buildMapContext.BundleInfos)
            {
                if (bundleInfo.IsRawFile == false)
                {
                    expectBundles.Add(bundleInfo);
                }
            }

            // 2. 验证数量
            if (buildedBundles.Length != expectBundles.Count)
            {
                Debug.LogWarning($"构建过程中可能存在无效的资源,导致和预期构建的Bundle数量不一致!");
            }

            // 3. 正向验证Bundle
            foreach (var bundleName in buildedBundles)
            {
                if (buildMapContext.IsContainsBundle(bundleName) == false)
                {
                    throw new Exception($"Should never get here !");
                }
            }

            // 4. 反向验证Bundle
            bool isPass = true;

            foreach (var expectBundle in expectBundles)
            {
                bool isMatch = false;
                foreach (var buildedBundle in buildedBundles)
                {
                    if (buildedBundle == expectBundle.BundleName)
                    {
                        isMatch = true;
                        break;
                    }
                }
                if (isMatch == false)
                {
                    isPass = false;
                    Debug.LogWarning($"没有找到预期构建的Bundle文件 : {expectBundle.BundleName}");
                }
            }
            if (isPass == false)
            {
                throw new Exception("构建结果验证没有通过,请参考警告日志!");
            }

            // 5. 验证Asset
            var buildMode = buildParameters.Parameters.BuildMode;

            if (buildMode == EBuildMode.ForceRebuild || buildMode == EBuildMode.IncrementalBuild)
            {
                int progressValue = 0;
                foreach (var buildedBundle in buildedBundles)
                {
                    string   filePath                = $"{buildParameters.PipelineOutputDirectory}/{buildedBundle}";
                    string[] allBuildinAssetPaths    = GetAssetBundleAllAssets(filePath);
                    string[] expectBuildinAssetPaths = buildMapContext.GetBuildinAssetPaths(buildedBundle);
                    if (expectBuildinAssetPaths.Length != allBuildinAssetPaths.Length)
                    {
                        Debug.LogWarning($"构建的Bundle文件内的资源对象数量和预期不匹配 : {buildedBundle}");
                        isPass = false;
                        continue;
                    }

                    foreach (var buildinAssetPath in allBuildinAssetPaths)
                    {
                        var guid = AssetDatabase.AssetPathToGUID(buildinAssetPath);
                        if (string.IsNullOrEmpty(guid))
                        {
                            Debug.LogWarning($"无效的资源路径,请检查路径是否带有特殊符号或中文:{buildinAssetPath}");
                            isPass = false;
                            continue;
                        }

                        bool isMatch = false;
                        foreach (var exceptBuildAssetPath in expectBuildinAssetPaths)
                        {
                            var guidExcept = AssetDatabase.AssetPathToGUID(exceptBuildAssetPath);
                            if (guid == guidExcept)
                            {
                                isMatch = true;
                                break;
                            }
                        }
                        if (isMatch == false)
                        {
                            Debug.LogWarning($"在构建的Bundle文件里发现了没有匹配的资源对象:{buildinAssetPath}");
                            isPass = false;
                            continue;
                        }
                    }

                    EditorTools.DisplayProgressBar("验证构建结果", ++progressValue, buildedBundles.Length);
                }
                EditorTools.ClearProgressBar();
                if (isPass == false)
                {
                    throw new Exception("构建结果验证没有通过,请参考警告日志!");
                }
            }

            // 卸载所有加载的Bundle
            BuildRunner.Log("构建结果验证成功!");
        }