/// <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(); } }
/// <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("构建结果验证成功!"); }